Compare commits

..
581 Commits
Author SHA1 Message Date
MervinPraison ebbb5f863e Release v0.3.149 2026-10-27 10:17:57 +00:00
Mervin Praison 34a01c1738 Merge pull request #318 from MervinPraison/fix/replay-unnamed-agents
fix(replay): map and narrate unnamed agents (Agent(instructions=...))
2026-10-27 11:14:51 +01:00
Mervin Praison 0d2b7b1d09 Merge branch 'main' into fix/replay-unnamed-agents 2026-10-27 11:13:04 +01:00
Mervin Praison 4ab1eee24f Merge pull request #319 from MervinPraison/fix/frontend-typecheck
fix(frontend): make the dashboard build pass again (26 type errors since April)
2026-10-27 11:12:54 +01:00
MervinPraisonandClaude Opus 5.5 1dad99b2c8 fix(frontend): make the dashboard build pass again (26 type errors since April)
The frontend build gate added on 2026-09-23 (166091b) has failed on every
main run since: five April PRs left code that never compiled — imports of
shadcn components that were never added (ui/alert, ui/textarea), seven
example widgets that never existed (CustomElementHost), react-router-dom
(not a dependency), a useSSE call written for a different hook, a wrong
ChatMessages prop set, and unused locals under noUnusedLocals.

- add the standard shadcn alert and textarea components
- CustomElementHost: empty registry instead of imports of missing widgets
- useWindowMessage: small local EventSource hook for /sse/window-message
- SharedThread: read the token from /shared/{token}; pass the props
  ChatMessages takes; type messages as ChatMessage[]
- drop unused imports/locals

None of these files are imported by the app today, so nothing users see
changes; the gate now builds and catches real breakage again.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-27 10:08:44 +00:00
MervinPraisonandClaude Opus 5.5 a89b00da5b fix(replay): map and narrate unnamed agents (Agent(instructions=...))
An agent created without name= records agent_name null. The Replay map
skipped every such event, so watch(Agent(instructions=...)) showed
"Nothing to map yet" and its steps were narrated as "The run".

- agentOf(ev): agent_name, else the package's id (agent:Agent from the
  companion core fix), else tool:None/<tool> or nothing in 4.7.19 traces,
  falling back to "Agent" for an agent's own run events.
- deriveGraph / nodeIdsForEvent / narrate use it, so the agent and its tools
  are drawn and lit, and steps read "Agent started.".
- Only when no graph was recorded: a team graph leaves unnamed agents out on
  purpose, and they must not reappear as "Outside the team".

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-27 09:46:43 +00:00
MervinPraison 706c934629 Release v0.3.148 2026-10-26 19:36:13 +00:00
Mervin Praison 7a22011892 Merge pull request #317 from MervinPraison/feat/replay-embed
feat(replay): embeddable Replay app, Run box, Play, and a map that follows the cursor
2026-10-26 17:35:07 +01:00
MervinPraisonandClaude Opus 5.5 7037cf7bd3 feat(replay): embeddable Replay app, Run box, Play, and a map that follows the cursor
- create_replay_app(run=None): the Replay view as a small ASGI app (no dashboard)
  to mount in any FastAPI/Starlette app; /?run=<id> pins one run (iframe-friendly).
  With run(input, run_id) it shows a Run box: POST /api/replay/run (JSON only,
  one run at a time) starts a run and the page follows it live.
- render(el, {base, run, runner, approve}) so the view works under a mount prefix.
- Map nodes show their state at the cursor: not reached / running / done / failed /
  skipped, and "×N" counts real runs instead of events (a step that ran once
  no longer reads "×2"). Scrubbing or Play rewinds the map with the cursor.
- ▶ Play steps through a run on its own.
- events?wait=1 answers a not-yet-started run without a 404.
- Node names stay whole (squeezed or clipped) so accessible names contain the
  visible text (WCAG 2.5.3; axe flagged truncated tool names).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 15:46:54 +00:00
Mervin Praison bf98d29a38 Merge pull request #316 from MervinPraison/feat/replay-view
feat(replay): PraisonAI Replay page (timeline, map, live, why, approvals) + trace-reader and UI-approval fixes
2026-10-26 14:44:22 +01:00
MervinPraisonandClaude Opus 5.5 fec821a306 docs(replay): rows, theme, map grouping and phone layout
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 12:24:25 +00:00
MervinPraisonandClaude Opus 5.5 e4a13c6dde fix(dashboard): phone layout and SVG page icons; Replay gets its own mark
- At <=1023 px the hidden sidebar still took 260 px of the flex row,
  because buildSidebar() sets an inline position:relative that beat the
  mobile position:fixed; and the shell header slot took another 53 px.
  Every page's content was squeezed to a few pixels at phone width. The
  sidebar is now fixed (!important), the header slot gets its own row,
  and phones get a 16 px gutter.
- Pages may set icon_svg next to the text icon. The sidebar and page
  header parse it as SVG and drop it if it holds scripts, foreignObject,
  on* handlers or javascript: URLs; other UIs keep using `icon`.
- Replay's heading uses its own inline mark (three lanes and a cursor)
  instead of the emoji, and its description no longer says "why" (it
  made Playwright's text=Why match the page header, not the tab).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 12:24:25 +00:00
MervinPraisonandClaude Opus 5.5 f1261958c8 fix(replay): real-run review — rows, system theme, fitted map, phone, export boot
From a review against real recorded runs:

- Timeline: an agent's LLM span encloses its tool calls in real runs, so
  tool blocks covered the LLM label. Each lane now has an LLM row with a
  thinner tool row under it, blocks are packed into tracks in pixel space
  so nothing overlaps, and labels are ellipsized; the full label is in
  the title, the accessible name and a hover/focus tip. Visible labels
  sit in a decorative layer so names never contain a cut-off word.
- Theme: defaults to the system setting (prefers-color-scheme, tracked
  live in CSS) with a System / Light / Dark menu as an override.
- Map: fits the whole graph on open (shares -/Fit/+), drag to pan, never
  below a readable scale, and gets the full width with the step list
  underneath. Agents seen in events but not in the graph (e.g. a
  hand-off to an agent outside the team) are added by observedGraph()
  and laid out by layoutRunMap() as an "Outside the team" group.
- Phone: 16 px gutter, stacked layout, no horizontal page scroll.
- Standalone boot waits for DOMContentLoaded so the export works with
  either script order, takes data.run_id as the title, and keeps the
  documented #replay-root / window.__REPLAY_DATA__ contract.
- New fixture team_outside.jsonl with the real-run shape; node tests
  for observedGraph/layoutRunMap; browser tests for no-overlap, the Why
  tab by role and keyboard, system theme, map fit, phone width and the
  wrapper-style export in both script orders.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 12:24:25 +00:00
MervinPraisonandClaude Opus 5.5 0e26b0ec8d fix(replay): fit narrow canvases and say "still waiting" for open items
The fit-to-width minimum (480 px of plot) made the timeline overflow in
the dashboard's narrower content column; lower it to 260 px. Pending
approvals and running blocks showed "Duration 0 ms"; show "still waiting"
or "still running" instead.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 11:38:42 +00:00
MervinPraisonandClaude Opus 5.5 bc3692ee69 docs(replay): user guide and clean-room ADR
docs/features/replay.md describes the page, keys, approvals, export and
HTTP API. docs/adr/0001-replay-view-clean-room.md records the ideas we
took (graph plus trace, score-like swimlanes, OTel GenAI vocabulary), that
no third-party UI code, CSS, icons, layouts or screenshots were used, and
the palette, accessibility and licence reasoning.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 11:36:14 +00:00
MervinPraisonandClaude Opus 5.5 6a64157d00 fix(approvals): UI approval backend waits for the human decision
_UIStoreBackend returned "Awaiting UI approval" (a denial) immediately, so
any tool needing approval was always denied and the UI's Approve button
never reached the agent. It also dropped request.approval_id and any
edited arguments.

- each request is stored under request.approval_id and the caller blocks
  until /api/approvals/{id}/approve|deny resolves it: sync callers on a
  threading.Event, async callers on a future of their own loop
- no answer before the timeout (registry timeout, default 300 s) is a
  denial and the entry is resolved as denied (fail-closed)
- a sync call made on an event-loop thread is denied at once rather than
  freezing that loop
- POST /approve accepts modified_args (object) and the decision carries
  it as ApprovalDecision(modified_args=...); the handler change is two
  lines so the auth checks in #312 rebase cleanly

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 11:36:14 +00:00
MervinPraisonandClaude Opus 5.5 3da3d3d547 fix(tracing): read recorded runs from the trace JSONL directory
SDKTracingManager looked up praisonaiagents.trace.list_traces, list_spans
and get_trace, which do not exist, so /api/traces never showed a recorded
run and silently fell back to an empty in-memory store.

JsonlTracingManager reads the same directory as Replay: one file is one
trace, spans come from start/end pairs (parent_seq on schema 1.1, sequence
order on 1.0), and records posted to /api/traces/record still work.
health() reports source: jsonl|memory. SDKTracingManager stays as a
deprecated alias.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 11:36:14 +00:00
MervinPraisonandClaude Opus 5.5 e46761e8a9 feat(replay): PraisonAI Replay feature and dashboard view
New `replay` feature (contract v1 §5), read-only:
- GET /api/replay/runs: run-picker rows, newest first, with a live flag
- GET /api/replay/runs/{id}/events?after_seq=N: {events, graph, run}
- GET /api/replay/runs/{id}/stream: SSE tail of the JSONL (stdlib seeks),
  `ctx` events with id=sequence_num, ping every 15 s, `end` after the run
  finishes plus 2 s quiet; honours after_seq and Last-Event-ID
- ids must match ^[A-Za-z0-9._-]+$ and resolve inside the traces dir
- traces dir: PRAISONAI_TRACES_DIR > PRAISON_HOME/traces > ~/.praison/traces
- half-written last lines, unknown fields/types and schema 1.0 are tolerated

Plain-JS view `replay` (no React, no CDN): replay-core.js holds pure
buildModel/narrate/layoutMap/deriveGraph (node --test); replay.js draws the
timeline (agent, Manager and You lanes, LLM/tool blocks, hand-off arrows,
parallel sub-lanes, xN repeats, task/step chapters, scrubber, live follow),
the narration list, What happened/Why/Raw JSON drawer, cost/latency
overlay, map view, and Approve/Deny/Edit-args for pending approvals.
Registered in BUILTIN_VIEWS and as a Control page; /#/replay?run=<id> deep
links resolve to /replay?run=<id>. It also boots standalone from
window.__REPLAY_DATA__; standalone_html() inlines both files for exports.

praisonaiui/replay_app.py + configure_replay_app() open aiui straight on
Replay for `praisonai replay view`.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 11:36:14 +00:00
Mervin PraisonandClaude Opus 5.5 6c156990f4 ci: bump github-automation-template to v1.1.19 (#315)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 11:42:31 +01:00
Mervin PraisonandClaude Opus 5.5 116425519e chore(ci): github-automation-template v1.1.18 (#314)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-26 09:46:39 +01:00
Mervin PraisonandClaude Opus 5.5 129adb9285 fix(ci): github-automation-template v1.1.17 (permission ceiling) (#310)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-17 09:34:51 +01:00
Mervin PraisonandClaude Opus 5.5 78deb698b6 chore(ci): github-automation-template v1.1.16 (#309)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-17 09:27:31 +01:00
b04e0e4c2c chore(ci): bump github-automation-template to v1.1.15 (#308)
Writers-only auto-Claude, least-privilege tokens for Claude on fork PRs and
in the merge-gate assessor, merge-gate held-out BLOCKs (no repeat verdicts on
an unchanged HEAD), portable prompts. auto-pr-comment sweep moves to hourly so
stale FINAL reviews are re-posted once a push settles.

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-16 16:58:34 +01:00
Mervin PraisonandClaude Opus 5.5 8bfcab2570 fix(ci): github-automation-template v1.1.14 (fork PR isolation) (#307)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-15 08:58:59 +01:00
Mervin PraisonandClaude Opus 5.5 83a1e10c4a fix(ci): require write access to invoke @claude (template v1.1.13) (#306)
Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-15 08:30:36 +01:00
f7d4eb8a13 chore: bump github-automation-template hub_ref to v1.1.11 (#305)
Picks up the 403 label fix in the hub callable workflows.

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-09-30 08:38:05 +01:00
Mervin Praison f254fefe95 Merge pull request #304 from MervinPraison/claude/issue-293-20260923
spike: evaluate BeautifulUI primitives in dev environment (#293)
2026-09-24 04:27:06 +01:00
Mervin Praison e22537fa38 Merge pull request #302 from MervinPraison/claude/issue-295-20260923
ci: add frontend build gate for BeautifulUI dashboard
2026-09-24 04:26:45 +01:00
MervinPraison b151143eb4 Release v0.3.147 2026-09-23 15:42:18 +00:00
praisonai-triage-agent[bot] 5949866103 Merge pull request #303 from MervinPraison/claude/issue-298-20260923
docs: BeautifulUI upgrade playbook and MIT attribution
2026-09-23 15:39:27 +00:00
praisonai-triage-agent[bot] b56bd87903 Merge pull request #300 from MervinPraison/claude/issue-294-20260923
fix: BeautifulUI adapter boundary + upstream pin policy (#294)
2026-09-23 15:39:07 +00:00
praisonai-triage-agent[bot] 0976d1caa3 Merge pull request #301 from MervinPraison/claude/issue-297-20260923
fix: render approvals view as accessible Approval Card (#297)
2026-09-23 15:38:53 +00:00
praisonai-triage-agent[bot] ef4a16ee68 Merge pull request #299 from MervinPraison/claude/issue-292-20260923
docs: BeautifulUI integration strategy (Epic #292)
2026-09-23 15:38:42 +00:00
MervinPraisonandClaude Opus 4.8 a3568bdb31 fix: normalize approval created_at epoch to ISO in agent-UI adapter
The /api/approvals payloads emit created_at as epoch seconds (time.time()),
but mapApprovalToCardProps used asString(), silently dropping the value for
real payloads so ApprovalPromptModel.createdAt was always undefined. Coerce
numeric epochs to an ISO-8601 string (ISO strings still pass through) and
align the unit test with the real wire shape.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 14:23:52 +00:00
MervinPraisonandClaude Opus 4.8 ffcb9da9df docs: fix vanilla chat plugin path in BeautifulUI strategy
Correct the fallback reference to templates/frontend/plugins/views/chat.js
(the file lives under views/, not directly under plugins/).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 14:23:22 +00:00
MervinPraisonandClaude Opus 4.8 afce1e542d docs: wire BeautifulUI playbook into aiui.template.yaml navigation
The shipped docs site is built by `aiui build` from aiui.template.yaml
(see ci.yml / deploy-pages.yml), not mkdocs.yml. Add a Frontend nav group
so the playbook is discoverable in the built site navigation.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 14:11:45 +00:00
MervinPraisonandClaude Opus 4.8 4d8f9b0322 fix: persist approval custom answer/option via reason field (#297)
The approve/deny endpoints only store `reason`; map the selected option or
typed custom answer into it so the human's decision note is recorded, while
keeping `option`/`custom_answer` for a future richer backend.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 14:10:13 +00:00
MervinPraisonandClaude Opus 4.8 a3a5e06225 test: make agent-UI adapter tests runnable via npm test (#294)
The adapter unit tests use Node's built-in runner, but the documented
command (`node --test src/agent-ui/`) fails on Node 22 — it neither
strips TypeScript types nor discovers the files, so the suite never ran.

- Add a `test` script to src/frontend that runs the suite with
  `--experimental-strip-types` (8/8 passing on Node 22).
- Fix the misleading run instructions in the test header.

Closes the "unit tests" acceptance criterion of #294 with an executable
suite. Purely additive; no runtime code changed.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 14:07:50 +00:00
MervinPraisonandClaude Opus 4.8 ec31577a38 spike: evaluate BeautifulUI primitives in dev environment (fixes #293)
Isolated, dev-only spike proving StreamingText, ThinkingState and
ApprovalCard build in src/frontend (React 19 + Vite + Tailwind v4) and
render against mock, PraisonAIUI-shaped agent event streams.

- Vendored 3 primitives + deps (button, glide-menu, foundation.css) under
  src/frontend/src/spike/beautifui/, imports rewritten to @/spike/* so
  nothing collides with the shipped components or the templates/frontend
  bundle (per issue non-goals).
- mockEvents.ts uses the real SSEEvent contract (run_content deltas,
  reasoning_step/tool_call_*, approval_request → /api/approvals).
- spike.html + SpikePage.tsx: `npm run dev` → /spike.html.
- Findings in src/frontend/src/spike/README.md: zero new runtime npm deps
  (liveline/glimm not pulled; @central-icons-react avoided — inline SVG),
  fixed an upstream unbalanced-brace bug in foundation.css, dropped the
  shadow-plugin dep, documented bundle size / reduced-motion / dark-mode.

Upstream pin: slev12397/beautiful-ui@44a274e598

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:52:48 +00:00
MervinPraisonandClaude Opus 4.8 1807595cd0 docs: add BeautifulUI upgrade playbook and MIT attribution (fixes #298)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:52:35 +00:00
MervinPraisonandClaude Opus 4.8 166091bc8e ci: add frontend build gate for BeautifulUI dashboard (fixes #295)
Adds a `frontend` job to CI that runs `npm ci && npm run build` for
src/frontend on every push/PR to main, failing on TypeScript/Vite build
errors. Uses Node 22 with npm caching keyed on the frontend lockfile.

Also documents the Node version, lockfile, and build/ship path in
src/frontend/README.md.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:50:39 +00:00
MervinPraisonandClaude Opus 4.8 aeefceeaa2 fix: render approvals view as accessible Approval Card (fixes #297)
- Add self-contained toApprovalModel() normalizer (ApprovalPromptModel shape)
- Render pending items as an Approval Card: risk accent, question, options,
  custom answer and confidence copy — surfaced only when the API supplies them
- Preserve /api/approvals approve|deny endpoints and skill-approval deep links
- Escape all interpolated API values via esc() (fixes prior XSS gap)
- Improve a11y: role=group/radiogroup, aria-labels on buttons/inputs

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:49:18 +00:00
MervinPraisonandClaude Opus 4.8 5b191a439b fix: add BeautifulUI adapter boundary + upstream pin policy (fixes #294)
Introduces the agent-UI adapter layer so BeautifulUI can be vendored
without leaking upstream types/paths across the frontend.

- src/frontend/src/agent-ui/contracts.ts: stable PraisonAIUI view models
  (AgentStreamEvent, ToolCallChipModel, ApprovalPromptModel)
- src/frontend/src/agent-ui/adapter.ts: pure mappers mapChatEventToUi()
  and mapApprovalToCardProps() from WS frames / approvals REST payloads
- src/frontend/src/agent-ui/adapter.test.ts: dependency-free unit tests
  (node:test, mock events -> props); 8 tests pass via `node --test`
- docs/frontend/: ADR (vendoring, adapter boundaries, folder layout,
  default-off feature flag + fallback) and upstream SHA/pin record
- mkdocs.yml: nav entries for the new frontend docs

Boundary rule: BeautifulUI prop types are imported only inside
src/agent-ui/; consumers depend on contracts.ts, keeping the vendored
implementation swappable. No new runtime deps; adapter is not yet
mounted (migration is #296/#297, CI gate is #295).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:47:39 +00:00
MervinPraisonandClaude Opus 4.8 0746ef5e6c docs: add BeautifulUI integration strategy (fixes #292)
Adds the durable integration strategy for the BeautifulUI epic: vendored
source (no runtime npm dep), adapter layer behind @praisonaiui/react,
phased flag-gated rollout, selective token merge, and lucide-react for
nav icons. Documents risks and links the child issues (#293-#298).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-23 13:41:43 +00:00
MervinPraisonandCursor 3058886312 chore: bump automation hub to v1.1.10 for merge gate fix
Co-authored-by: Cursor <[email protected]>
2026-09-22 15:30:07 +01:00
Mervin Praison 70d8610733 Merge pull request #291 from MervinPraison/claude/issue-290-20260916
docs: add SECURITY.md with private disclosure policy
2026-09-17 10:37:03 +01:00
MervinPraison 0f60ec41f1 Release v0.3.146 2026-09-17 03:02:10 +00:00
MervinPraisonandClaude Opus 4.8 2797667e04 docs: add SECURITY.md with private disclosure policy (fixes #290)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-16 16:28:01 +00:00
Mervin Praison f23aacdec9 Merge pull request #289 from MervinPraison/claude/issue-286-20260915
fix: auto-load ~/.praisonai/.env on aiui run so env: channel tokens resolve
2026-09-16 14:43:31 +01:00
MervinPraison 17cd4d9f86 Release v0.3.145 2026-09-16 13:00:52 +00:00
Mervin Praison 43935e4e41 fix: forward extra kwargs through channels chat bridge (fixes #287)
fix: forward extra kwargs through channels chat bridge (fixes #287)
2026-09-16 13:58:08 +01:00
MervinPraisonandClaude Opus 4.8 8dc8b9f49f fix: auto-load ~/.praisonai/.env on aiui run so env: tokens resolve (fixes #286)
Channels configured with env:VAR token references silently resolved to
empty strings when the dashboard was started without the shell exporting
the tokens, so bots showed 'Connected' but never replied. aiui run now
loads the standard PraisonAI .env files (~/.praisonai/.env, then ./.env)
into the process environment at startup, matching the PraisonAI CLI
convention. Existing process vars are never overridden and parsing is
dependency-free (no python-dotenv).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-15 13:16:37 +00:00
MervinPraisonandClaude Opus 4.8 135b05435c fix: forward extra kwargs through channels chat bridge (fixes #287)
The chat bridge installed over bot._session.chat used a fixed
(agent, user_id, text) signature. When the bot internals invoked the
session with per-conversation keyword arguments (chat_id, platform,
thread_id, ...) the wrapper raised
`TypeError: _wrapped_chat() got an unexpected keyword argument 'chat_id'`
and the bot silently failed to reply across all platforms (Telegram,
Slack, Discord).

Add `*args, **kwargs` to `_wrapped_chat` and forward them untouched to
the original session chat so memory/session continuity is preserved.
Minimal, backward-compatible change; no new params or dependencies.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-15 13:11:51 +00:00
MervinPraisonandCursor be502d823f chore(automation): bump hub to v1.1.8 for dual OAuth failover
Uses pick-oauth-token pre-flight probe and TOKEN_B backup.

Co-authored-by: Cursor <[email protected]>
2026-09-15 07:49:29 +01:00
Mervin Praison 9be1266747 Merge pull request #285 from MervinPraison/fix/voice-doctor-mcp-probe-timeout
fix(voice-agent): warn on slow MCP doctor probe instead of failing
2026-09-14 17:45:00 +01:00
MervinPraisonandCursor 8ce13a9fec fix(voice-agent): warn on slow MCP doctor probe instead of failing
Use a 2s timeout for GET /api/mcp/servers and downgrade timeout-style
errors to warn so stdio MCP connect does not fail the whole doctor run.

Follow-up to #273 (example-only; no core SDK changes).

Co-authored-by: Cursor <[email protected]>
2026-09-14 14:51:08 +01:00
Mervin Praison e6a346aa22 Merge pull request #284 from MervinPraison/chore/automation-hub-v1.1.7
chore(automation): bump github-automation-template hub to v1.1.7
2026-09-14 14:22:51 +01:00
MervinPraisonandCursor b7b0cc2109 chore(automation): bump github-automation-template hub to v1.1.7
Fixes FINAL detection and triggerLogins fallback for merge gate auto-merge.

Co-authored-by: Cursor <[email protected]>
2026-09-14 14:22:39 +01:00
MervinPraison dc0d81fb55 Release v0.3.144 2026-09-14 13:19:10 +00:00
Mervin Praison 032f3832a7 Merge pull request #283 from MervinPraison/claude/issue-274-20260914
fix: wire chat run abort (populate _active_runs) — fixes #274
2026-09-14 14:17:05 +01:00
Mervin Praison 0c282f5268 Merge pull request #282 from MervinPraison/claude/issue-276-20260914
fix: prevent MCP subprocess leak on reconnect and failed connect
2026-09-14 14:17:02 +01:00
Mervin Praison 85f50ff9b8 Merge pull request #281 from MervinPraison/claude/issue-277-20260914
fix: make _start_channel_bot idempotent to prevent duplicate bots
2026-09-14 14:16:59 +01:00
Mervin Praison 6b79a346a7 Merge pull request #280 from MervinPraison/claude/issue-275-20260914
fix: preserve channel message metadata in SDKFileDataStore
2026-09-14 14:16:56 +01:00
Mervin Praison f2dec3bc81 Merge pull request #279 from MervinPraison/claude/issue-278-20260914
fix: bound @aiui.on_startup hooks with AIUI_STARTUP_TIMEOUT
2026-09-14 14:16:53 +01:00
Mervin Praison 169c0c2eb0 feat(voice-agent): Phases 1–4 — telephony, call analytics, doctor, and MCP manager (#272)
feat(voice-agent): Phases 1–4 — telephony, call analytics, doctor, and MCP manager
2026-09-14 14:15:23 +01:00
MervinPraisonandClaude Opus 4.8 1de8d054a8 fix: remove stale gateway task on channel bot restart (#277)
_start_channel_bot registers the task in gateway _channel_tasks, but
_stop_channel_bot only cleaned up _channel_bots. For the list-based
gateway registry this left the old cancelled task appended on every
restart, accumulating orphaned task references. Mirror start-time
registration by removing the task from _channel_tasks (dict pop / list
remove) on stop. Adds regression tests for both dict and list forms.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-14 10:21:01 +00:00
MervinPraisonandClaude Opus 4.8 9ac4414901 fix: register chat runs in _active_runs so abort works (fixes #274)
_run_and_broadcast never inserted its task into ChatManager._active_runs
and never emitted run_started, so the Stop button, POST /api/chat/abort,
and the chat_abort WS message always returned no_active_run while tokens
were still streaming.

- Register the running task under run_id at run start
- Broadcast run_started up-front so the frontend captures run_id and can
  enable the Stop button before the first token
- Deregister the run in a finally on completion, error, or abort

Existing CancelledError handler already broadcasts run_cancelled once the
task is actually cancelled.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-14 09:51:06 +00:00
MervinPraisonandClaude Opus 4.8 5168ea253a fix: disconnect MCP client on reconnect and failed connect to prevent subprocess leak (fixes #276)
Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-14 09:48:12 +00:00
MervinPraisonandClaude Opus 4.8 a739ba8a6c fix: make _start_channel_bot idempotent to prevent duplicate bots (fixes #277)
Add a guard at the top of ChannelsFeature._start_channel_bot that stops any
bot already running for the same channel_id before creating a new one. This
prevents duplicate bots (with duplicate event handlers) when a channel is
toggled off/on, re-added, or when autostart races with a manual start.

Also make _stop_channel_bot await the cancelled task so the previous bot is
fully torn down before a restart proceeds, eliminating zombie asyncio tasks.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-14 09:47:54 +00:00
MervinPraisonandClaude Opus 4.8 4f8ea88a5c fix: preserve channel message metadata in SDKFileDataStore (fixes #275)
SDKFileDataStore only copied toolCalls/elements into SDK message
metadata on write and only restored those two keys on read, so
channel/voice fields (platform, sender, icon, channel_id) were
silently dropped after reload — despite being persisted correctly by
the SQLAlchemy backend.

Write path now preserves all non-core keys (excluding None), and the
read path restores every persisted metadata key (skipping internal
sentinel keys, without clobbering role/content), matching the
SQLAlchemy backend. Backward compatible: existing toolCalls/elements
round-trips are unchanged and no migration is required.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-14 09:47:29 +00:00
MervinPraisonandClaude Opus 4.8 112253013a fix: add AIUI_STARTUP_TIMEOUT to bound startup hooks (fixes #278)
Startup hooks ran with an unbounded await while shutdown hooks were
already protected by AIUI_SHUTDOWN_TIMEOUT. A single hung startup hook
blocked the Starlette lifespan from reaching yield, so /health/live never
responded and the dashboard never loaded.

Mirror the shutdown pattern: wrap startup hooks in asyncio.wait_for with
AIUI_STARTUP_TIMEOUT (default 60s). On timeout, log the error and mark
startup completed so the server still reaches lifespan yield. Shutdown
behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-14 09:47:16 +00:00
MervinPraisonandClaude Opus 4.8 ac88e1cab7 fix(mcp): close partially-entered exit stack on connect cancellation/timeout
Store the AsyncExitStack on self._exit_stack before entering the stdio/SSE
contexts. On an asyncio.wait_for timeout the inner connect() is cancelled with
CancelledError (a BaseException), which bypasses the except-Exception cleanup,
so self._exit_stack was never set and MCPClientManager.connect()'s timeout
branch called client.disconnect() as a no-op — leaking the stdio subprocess /
SSE streams. Assigning the stack up front lets disconnect() always close it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-10 18:55:52 +00:00
MervinPraisonandClaude Opus 4.8 14ca101086 fix(mcp): catch asyncio.TimeoutError so connect timeout works on Python 3.10
asyncio.wait_for raises asyncio.TimeoutError, which is only aliased to
the builtin TimeoutError on Python 3.11+. On the 3.10 CI leg the bare
'except TimeoutError' missed it, so the timeout fell through to the
generic handler with an empty last_error and no client.disconnect()
cleanup. Catch asyncio.TimeoutError to restore the helpful message and
subprocess/stream cleanup across all supported Pythons.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-10 18:40:48 +00:00
Dhivya-Bharathy 30f046d0fb feat(voice-agent): Phases 2-4, call analytics, doctor, and MCP connect fix 2026-09-10 16:24:20 +05:30
Mervin Praison 597280a6c6 Merge pull request #265 from Dhivya-Bharathy/feat/meeting-agent-phase-2-recall
feat(meeting-agent): Phase 2 Recall.ai live bots (Part A)
2026-09-08 16:39:01 +01:00
MervinPraisonandClaude Opus 4.8 fe954cbd4a fix(meeting-agent): drop leftover hardcoded Recall workspace UUID from part_b test
The personal contributor workspace UUID (33a035c7-...) was still hardcoded
in the test_meeting_agent_part_b.py env fixture, even though the same value
was cleaned to a neutral placeholder everywhere else (config default,
.env.example, smoke_recall.py, and test_meeting_agent_recall.py). Aligned it
with the sibling test's 'test-workspace' placeholder. No assertion depends on
the value, so behavior is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-08 09:43:30 +00:00
MervinPraisonandClaude Opus 4.8 ab9ef2544d fix(meeting-agent): point Part B tests at renamed meeting_integrations dir
The Part A branch renamed integrations/recall -> meeting_integrations/recall
to avoid a tests/unit/integrations module-name collision, but the Part B test
loaders (test_meeting_agent_part_b.py) still resolved the old integrations/recall
paths, raising FileNotFoundError on CI (py3.10/3.11/3.12). Repoint the 9 _load()
paths at meeting_integrations/recall to match the source layout and the already-
updated test_meeting_agent_recall.py.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-08 09:39:03 +00:00
MervinPraisonandCursor e15b3c0718 merge: resolve conflicts with main (Part B + voice-agent merged)
Reconcile meeting-agent Phase A with main after #266/#267: keep
meeting_integrations/ package rename, merge Part B live-transcript and
Calendar V2 routes, and preserve Part A fixes (atomic webhook idempotency,
background task refs, workspace ID placeholders, py3.10 compiler compat).
Update part_b tests to meeting_integrations paths.

Co-authored-by: Cursor <[email protected]>
2026-09-08 10:34:47 +01:00
MervinPraison 6ecb80e977 Release v0.3.143 2026-09-08 09:05:53 +00:00
Mervin Praison 7ebd97d359 Merge pull request #266 from Dhivya-Bharathy/feat/meeting-agent-phase-2-part-b
feat(meeting-agent): Phase 2 Part B — live transcript + Calendar V2
2026-09-08 10:04:46 +01:00
Mervin Praison bd6b67f38b Merge pull request #267 from Dhivya-Bharathy/feat/voice-agent-phase-1
feat(voice-agent): Phase 1 telephony webhooks, tools, and call dashboard
2026-09-08 10:03:17 +01:00
MervinPraisonandClaude Opus 4.8 442e2d6dfe fix(meeting-agent): retain strong refs to webhook background tasks
asyncio keeps only weak references to tasks created via create_task, so a
fire-and-forget webhook dispatch could be garbage-collected mid-execution and
silently drop the event (a transcript line persist or the post-transcript
pipeline). Route both Recall and calendar webhook dispatches through a helper
that holds a strong reference in a module-level set until the task completes.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-08 08:17:46 +00:00
MervinPraisonandClaude Opus 4.8 3608d011c6 fix(voice-agent): build stable webhook idempotency keys so status updates aren't dropped
webhook_event_key derived the dedup key from a 200-char JSON prefix for
status-update/conversation-update/end-of-call-report. When a large static
field (e.g. `call`) sorts before the discriminating field, successive
events collapse to the same prefix and later ones are dropped as
duplicates, freezing the dashboard status on the first value (e.g. stuck
on 'ringing'). Derive keys from the fields that actually distinguish each
event, matching the existing transcript-event pattern. No new deps,
params, or exports.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 23:45:23 +00:00
MervinPraisonandClaude Opus 4.8 d615e2e0a3 fix(tests): warm up liveness endpoint before timing to fix flaky 3.10 CI
test_health_live_is_fast timed the first request through the Starlette
TestClient, which pays one-time route/client initialization cost and
measured 0.15s on a slow Python 3.10 runner (threshold 0.1s). Add a
warmup request so the assertion measures steady-state latency, matching
the endpoint's own <500ms target. No production code change.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 19:26:06 +00:00
MervinPraison 352023db8d fix(meeting-agent): serialize live-transcript metadata read-modify-write
Recall webhooks are dispatched one-thread-each via asyncio.to_thread, so
rapid-fire transcript.data events ran _upsert_live_transcript concurrently.
Each did an unsynchronized read (get_meeting) -> append -> UPDATE of the
persisted meeting transcript, so two concurrent captions could read the same
base and one write would clobber the other, dropping transcript lines.

Add a shared reentrant lock (pipeline._metadata_lock) around every metadata
read-modify-write in merge_meeting_metadata, and hold it across the read in
_upsert_live_transcript so the whole read-append-write is atomic. In-memory
fan-out (live.py) already had a lock; this closes the same gap for the
persisted transcript. Example-only, no package params/exports/deps added.
2026-09-07 19:23:01 +00:00
MervinPraisonandClaude Opus 4.8 bfb1eeee06 fix(voice-agent): preserve live call status on transcript/conversation events
upsert_call overwrote status with excluded.status and defaulted to
'unknown', so transcript and conversation-update events (which pass no
status) reset an in-progress call to 'unknown' in the dashboard. Preserve
the prior status when the caller omits one, matching the existing
COALESCE handling for summary/customer_number. Adds a regression test.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 19:21:10 +00:00
MervinPraisonandClaude Opus 4.8 12b42e88be fix(meeting-agent): make Recall webhook idempotency check atomic
Replace the non-atomic SELECT-then-INSERT in mark_event_processed with an
atomic INSERT OR IGNORE + rowcount check. Under concurrent duplicate webhook
deliveries (Svix retries/fan-out) both callers could pass the SELECT and the
second INSERT would raise an unhandled IntegrityError on the primary key,
silently dropping that event's processing after a 200 was returned.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:29:26 +00:00
MervinPraisonandClaude Opus 4.8 5e80f11535 fix(meeting-agent): drop hardcoded personal Recall workspace ID from example
The RECALL_WORKSPACE_ID default was a real contributor workspace UUID
committed across the example (config default, README, .env.example, smoke
script, test). It is non-functional — the Recall API key already scopes
requests to a workspace and the value is only echoed back by the
config-status endpoint. Default it to an empty string and replace the
committed UUID with neutral placeholders.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:25:58 +00:00
MervinPraisonandClaude Opus 4.8 84ae1fd0ac fix(meeting-agent): retain webhook background task refs to prevent GC
asyncio only holds weak references to tasks created via create_task, so the
fire-and-forget Recall webhook processing task could be garbage-collected
mid-execution, silently dropping transcript/status updates. Keep strong refs
in a module-level set and discard on completion.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:21:44 +00:00
MervinPraisonandClaude Opus 4.8 b59af41d88 fix(compiler): use timezone.utc for Python 3.10 compatibility
datetime.UTC was added in Python 3.11, so importing it broke the
python (3.10) CI job with ImportError in _format_lastmod. Switch to
timezone.utc which is equivalent and available on all supported
Python versions (3.10+).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:17:41 +00:00
MervinPraisonandClaude Opus 4.8 fb999aba3c fix(seo): use timezone.utc for Python 3.10 compatibility in sitemap lastmod
datetime.UTC was added in Python 3.11, but requires-python is >=3.10, so
Compiler._format_lastmod raised ImportError on 3.10, failing the SEO build
tests and blocking CI. timezone.utc is equivalent and available since 3.2.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:15:55 +00:00
MervinPraisonandClaude Opus 4.8 8e5c4d40e2 fix(meeting-agent): resolve CI failures on Phase 2 Recall PR
- Rename example package integrations/ -> meeting_integrations/ to avoid a
  top-level module-name collision with tests/unit/integrations (imported as
  top-level 'integrations' because tests/unit has no __init__.py). The
  collision made 'meeting_integrations.recall' unresolvable once the test
  session imported the tests integrations package first, causing 8 errors +
  3 failures. Updated all absolute imports and test path references.
- Guard praisonai_tools-dependent tests with pytest.importorskip: the meeting
  tools live in the external PraisonAI-Tools package and are not installed in
  this repo's CI, so those tests skip cleanly instead of erroring.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:15:01 +00:00
MervinPraisonandClaude Opus 4.8 c7dc8a751a fix(tests): skip meeting-agent tests when praisonai_tools is unavailable
The 6 new meeting-agent tests invoke the external PraisonAI-Tools
'meeting_tools' module, which is not a PraisonAIUI CI dependency, causing
ModuleNotFoundError failures on Python 3.10/3.11/3.12. Guard them with
pytest.importorskip so CI skips them cleanly instead of failing, matching
how the example treats its other optional heavy deps.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 15:11:50 +00:00
MervinPraisonandClaude Opus 4.8 b5b640a2b7 fix(compiler): use timezone.utc for lastmod so Python 3.10 CI passes
datetime.UTC was added in Python 3.11, but the project supports >=3.10
(CI matrix + classifiers), so _format_lastmod raised ImportError on 3.10:
  cannot import name 'UTC' from 'datetime'
Switch to timezone.utc (available since 3.2) — identical behaviour, all
supported versions. Fixes the failing python (3.10) job on PR #267.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 10:21:44 +00:00
MervinPraisonandClaude Opus 4.8 a188039480 fix(voice-agent): hold strong ref to background webhook task to prevent GC drop
asyncio only keeps a weak reference to tasks created via create_task, so a
fire-and-forget webhook-processing task could be garbage-collected mid-flight
and silently drop a status/transcript event. Track tasks in a set and discard
on completion (standard asyncio pattern).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 10:16:51 +00:00
MervinPraisonandClaude Opus 4.8 c71ad7d6da fix(voice-agent): isolate example package import in unit tests to fix CI
tests/unit/integrations ships a top-level 'integrations' package, which
shadowed the voice-agent example's integrations.voice package when the
voice test ran after the integration tests (ModuleNotFoundError: No module
named 'integrations.voice'), failing python 3.10/3.11/3.12 CI.

Import the example's modules inside a context manager that gives the
example dir priority on sys.path and restores the original 'integrations'
package afterwards. Example code is unchanged.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 10:13:46 +00:00
MervinPraisonandClaude Opus 4.8 ecf2118bb2 fix(voice-agent): remove committed run logs, timing-safe webhook verify, lazy httpx
- Delete accidentally committed .app.err / .tunnel.log.err (leaked local
  paths, Cloudflare tunnel URLs, connector IDs); ignore *.err
- verify.py: use hmac.compare_digest for constant-time secret comparison
- client.py: lazy-import httpx (optional dep) per AGENTS.md lazy-import rule
- Fix import ordering (ruff I001) in app.py / voice_routes.py

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-09-07 10:06:59 +00:00
Mervin Praison 43722c4901 Merge pull request #271 from MervinPraison/chore/hub-v1.1.6
chore(ci): hub v1.1.6 — fix Claude Assistant hub checkout
2026-09-07 11:02:21 +01:00
MervinPraisonandCursor 798e893153 chore(ci): bump hub to v1.1.6 (claude-code-action checkout fix)
Co-authored-by: Cursor <[email protected]>
2026-09-07 11:02:16 +01:00
Mervin Praison 696455db7b Merge pull request #270 from MervinPraison/chore/hub-v1.1.5
fix(ci): hub v1.1.5 Claude Assistant caller permissions
2026-09-07 11:00:42 +01:00
MervinPraisonandCursor 9735e1c4af fix(ci): hub v1.1.5 — Claude Assistant caller permissions
Co-authored-by: Cursor <[email protected]>
2026-09-07 11:00:33 +01:00
Mervin Praison effc3982d6 Merge pull request #269 from MervinPraison/chore/hub-v1.1.4
fix(ci): hub v1.1.4 caller permissions for Claude review chain
2026-09-07 10:59:06 +01:00
MervinPraisonandCursor e67075b799 fix(ci): hub v1.1.4 — grant reusable-workflow caller permissions
Repos with default_workflow_permissions: read reject Auto PR Comment and merge
gate when the caller only grants pull-requests: read but callee jobs need write.

Co-authored-by: Cursor <[email protected]>
2026-09-07 10:58:56 +01:00
Mervin Praison 993114bb55 Merge pull request #268 from MervinPraison/chore/hub-v1.1.3
chore(ci): bump github-automation hub to v1.1.3
2026-09-07 10:53:23 +01:00
MervinPraisonandCursor 8c59d2db85 chore(ci): bump github-automation hub to v1.1.3
Fixes broken reusable workflow refs (v1.1.1 dynamic hub-setup) and review-chain
callable YAML so Auto PR Comment / merge gate / CI-failure Claude run again.

Co-authored-by: Cursor <[email protected]>
2026-09-07 10:53:05 +01:00
Dhivya-Bharathy dc98a79f6e feat(voice-agent): Phase 1 telephony webhooks, tools, and call dashboard 2026-09-07 13:18:37 +05:30
Dhivya-BharathyandCursor ced5a52871 feat(meeting-agent): Phase 2 Part B — live transcript + Calendar V2
Co-authored-by: Cursor <[email protected]>
2026-09-04 17:55:33 +05:30
Dhivya-BharathyandCursor 5f3b026da8 feat(meeting-agent): Phase 2 Recall.ai live bots (Part A)
Add Recall integration for live Google Meet/Zoom/Teams capture: bot scheduling, verified webhooks, async transcription, and post-call summarize + index pipeline. Includes recovery script, smoke mode, and unit tests. Phase 1 upload flow unchanged.

Co-authored-by: Cursor <[email protected]>
2026-09-04 10:59:01 +05:30
MervinPraisonandCursor 15aa219cb3 chore(automation): upgrade to hub v1.1.1 and fix pre-labelled issue Claude trigger
Switch merge-gate, review chain, CI failure, and pipeline workflows to thin
hub callers. Fix auto-issue-comment and claude-dedupe so bot-routed issues
opened with the claude label still dispatch Claude.

Co-authored-by: Cursor <[email protected]>
2026-09-02 13:08:41 +01:00
Mervin Praison 5c88692009 Merge pull request #261 from MervinPraison/claude/issue-260-20260902-meeting-ui
feat: thin meeting-agent UI example (PAI-MEET-UI)
2026-09-02 10:33:55 +01:00
praisonai-triage-agent[bot]andMervin Praison 83c273eba3 fix(compiler): remove extraneous f-string prefix breaking ruff (CI)
CI job `python (3.12)` failed at `ruff check src/praisonaiui` with F541
(f-string without placeholders) on compiler.py:922, blocking pytest before
it ran. Removed the unnecessary `f` prefix on the static og:type meta tag.

Co-authored-by: Mervin Praison <[email protected]>
2026-09-02 09:31:10 +00:00
MervinPraisonandClaude ee44c38297 feat: add thin meeting-agent UI example composing existing features (fixes #260)
Adds examples/python/meeting-agent/ wiring existing attachments, knowledge,
chat and Slack features via YAML/config only. No new package, no new public
exports, no create_app()/server.py params, no eager heavy deps.

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

Co-Authored-By: Claude <[email protected]>
2026-09-02 09:26:05 +00:00
Mervin Praison 8a79913cc4 Merge pull request #228 from MervinPraison/claude/issue-222-20260715-1318
feat: Training Lab UI for praisonai-train agent sessions (STITCH-012)
2026-09-02 10:09:12 +01:00
Mervin Praison af97f31e68 Merge pull request #229 from MervinPraison/claude/issue-217-20260715-run-recorder
feat: Run Flight Recorder — /runs three-pane run debugger (#217)
2026-09-02 10:09:00 +01:00
MervinPraisonandCursor 812c53abaa fix(docs): prevent stale content and full reloads on fast navigation
Abort in-flight markdown fetches, clear the article immediately on route change, and always intercept sidebar links so rapid clicks stay in the SPA instead of showing the wrong page.

Co-authored-by: Cursor <[email protected]>
2026-08-28 12:54:38 +01:00
MervinPraisonandCursor 4bc7497e99 feat(docs): Mintlify-style full-width layout and header navigation
Adopt a three-column docs shell with a centred 720px content column, integrated header tabs, search, and tab-filtered sidebar so navigation matches Mintlify-style sites.

Co-authored-by: Cursor <[email protected]>
2026-08-28 11:16:35 +01:00
MervinPraisonandCursor 4bf74be9c7 fix(docs): render Mermaid diagrams full width like Mintlify
Use useMaxWidth, measure the container width on render/resize, and scale
SVG to 100% of the content column. Widen the docs main area by removing
max-w-3xl so diagrams use space between sidebar and TOC.

Co-authored-by: Cursor <[email protected]>
2026-08-28 10:23:12 +01:00
MervinPraisonandCursor 800883aaf4 test: assert mermaid renders via code component unwrap
Co-authored-by: Cursor <[email protected]>
2026-08-27 14:58:06 +01:00
MervinPraisonandCursor fc28c77e84 fix(docs): detect mermaid fences in code component
Route ```mermaid blocks through the code markdown handler so diagrams
render reliably across react-markdown versions, with pre unwrapping the
MermaidDiagram output.

Co-authored-by: Cursor <[email protected]>
2026-08-27 14:47:03 +01:00
MervinPraisonandCursor 82980cee1a fix(docs): render Mermaid diagrams in React SPA
The mermaid plugin skips React-managed article content to avoid DOM
reconciler crashes, so fenced mermaid blocks showed as raw code. Add a
native MermaidDiagram component with lazy-loaded mermaid@11, theme sync,
and bundled frontend assets.

Co-authored-by: Cursor <[email protected]>
2026-08-27 14:37:34 +01:00
MervinPraisonandCursor 6bfc19a0ee fix(ci): use force_orphan for reliable GitHub Pages deploys
peaceiris was rm-ing gh-pages files then skipping commit when the tree
matched HEAD, leaving llms.txt and sitemap offline. force_orphan replaces
the branch on every deploy.

Co-authored-by: Cursor <[email protected]>
2026-08-26 22:28:25 +01:00
MervinPraisonandCursor 6f855aee3e feat(seo): complete crawl readiness — llms-full, lastmod, auto descriptions
Add llms-full.txt, sitemap lastmod dates, auto meta descriptions from first
paragraph, per-page noindex support, runtime JSON-LD/OG/Twitter updates, a
dedicated Deploy Docs workflow, and corrected SEO documentation.

Co-authored-by: Cursor <[email protected]>
2026-08-26 22:22:09 +01:00
MervinPraisonandCursor 203c57710a ci: allow manual workflow dispatch for docs deploy
Push webhooks stopped firing CI after 13:32 UTC; workflow_dispatch
lets us redeploy GitHub Pages with sitemap, robots.txt, and llms.txt.

Co-authored-by: Cursor <[email protected]>
2026-08-26 17:21:52 +01:00
MervinPraisonandCursor bd6d08b08e feat(seo): add llms.txt, crawl nav, and homepage sitemap entry
Generate llms.txt for AI crawlers, inject static nav links into prerendered
HTML, convert markdown links in noscript content, and include the site root
in sitemap.xml so Google can discover all doc pages once deployed.

Co-authored-by: Cursor <[email protected]>
2026-08-26 17:20:59 +01:00
MervinPraisonandCursor 90feb197b2 fix(docs): stop plugin DOM mutations that crash React SPA navigation
Guard plugin-loader, syntax-highlight, mermaid, and code-copy from touching
React-managed article content; emit flat doc HTML for canonical URLs; add SEO
sitemap/robots and trailing-slash normalisation so sidebar clicks stay stable.

Co-authored-by: Cursor <[email protected]>
2026-08-26 17:17:18 +01:00
MervinPraisonandCursor a391d55f74 fix(frontend): fetch content only when currentPath changes
Avoid re-running the markdown fetch when selectedItem syncs after
aiui:navigate, which was cancelling requests and leaving loading stuck.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:32:03 +01:00
MervinPraisonandCursor a5e6316021 fix(frontend): unstick "Loading content..." after SPA navigation
Reset loadingContent in effect cleanup when a fetch is cancelled, and
fetch only on currentPath changes so selectedItem sync does not abort
the in-flight request.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:31:48 +01:00
MervinPraisonandCursor 3c534c9637 fix(frontend): map /docs/index to /docs/index.md not /docs.md
Stripping a trailing /index segment broke the docs home page fetch,
causing "Content for PraisonAIUI not found" at /docs/index.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:30:49 +01:00
MervinPraisonandCursor e2486fe666 fix(frontend): stop empty pages and stale content on SPA nav
React now owns sidebar navigation content: sync selectedItem on
aiui:navigate, fetch markdown from currentPath with cancel-on-nav,
use canonical URLs without trailing slashes, and add data-nav-path on
sidebar buttons. Plugins teardown hide-mode instead of replacing React
DOM; mkdocs-compat no longer wipes main.flex-1.

Co-authored-by: Cursor <[email protected]>
2026-08-26 14:08:55 +01:00
MervinPraisonandCursor 60e9bbe2df fix(frontend): wrap theme tokens in hsl() so backgrounds render
Tailwind utilities used var(--background) directly, but shadcn tokens
store bare HSL components — backgrounds were transparent while prose
text used hsl(var(--foreground)), causing light-on-white in dark mode.
Also replace hardcoded dark anti-flicker with localStorage-aware bootstrap.

Co-authored-by: Cursor <[email protected]>
2026-08-26 12:07:06 +01:00
MervinPraisonandCursor 672070cd13 fix(frontend): restore light-mode contrast on plugin SPA path
Align content-loader and homepage plugins with React prose classes,
extend CSS contrast rules to all article.prose, fix server anti-flicker
hardcoded dark colours, wire theme toggle with localStorage, and add
guardrail tests for the plugin rendering path.

Co-authored-by: Cursor <[email protected]>
2026-08-26 11:23:46 +01:00
MervinPraisonandCursor db0672feec fix(frontend): restore light-mode prose and code contrast
Scope mermaid heading overrides to dark mode, fix hsl() theme tokens in
syntax-highlight, and force readable prose colours for body text, tables,
and code blocks in light mode.

Co-authored-by: Cursor <[email protected]>
2026-08-26 07:50:25 +01:00
MervinPraison 7fe03534de Release v0.3.142 2026-08-26 01:00:01 +00:00
MervinPraisonandCursor 23a193eb22 fix(frontend): complete docs UI P1 — routing, nav, TOC, mermaid
Wire route-manifest template resolution, mobile nav drawer, live TOC from
page headings, Mermaid async rendering via aiui:content-loaded, and
FlexibleLayout footer deduplication.

Co-authored-by: Cursor <[email protected]>
2026-08-25 23:58:43 +01:00
MervinPraison b6dc50180b Release v0.3.141 2026-08-25 22:48:37 +00:00
MervinPraisonandCursor d91c3baf21 fix(frontend): improve docs UI contrast and MkDocs rendering
Fix unreadable light-mode code blocks, transform MkDocs Material syntax
(tabs, icons, grid cards) in both React and plugin paths, and auto-select
nav items from the URL including top-level entries like /docs/index.

Co-authored-by: Cursor <[email protected]>
2026-08-25 23:45:46 +01:00
MervinPraisonandCursor 5c9e8b2356 docs(adp): harden protocol spec after multi-agent validation
Split component catalog schema from instance data, fix theme/slots
validation, clarify navigation model, add implementation status and
CI tests for ADP JSON Schema conformance.

Co-authored-by: Cursor <[email protected]>
2026-08-25 22:47:42 +01:00
MervinPraison a48f3ae4b2 fix(ci): enhance merge gate recovery and streamline auto-merge process 2026-08-25 22:40:35 +01:00
MervinPraison b4d705ce12 fix(ci): recognise Claude replies and unblock stale-FINAL after rebase
Port merge-gate recovery fixes from PraisonAI-Tools so auto-merge resumes after
conflict rebase pushes and MervinPraison Claude finished comments count.
2026-08-15 13:33:36 +01:00
MervinPraison 88c84d0c35 Release v0.3.140 2026-08-01 02:22:54 +00:00
MervinPraison 6d71fa4197 fix: port full scope-creep gates from PraisonAI with UI wording
Align merge gate, conflict/CI fix prompts, FINAL phases, and claude.yml
with PraisonAI lightweight-and-powerful checks — product value, layering
(praisonaiagents / PraisonAI-Tools), and server.py bloat — not Agent-class.
2026-07-31 14:04:16 +01:00
praisonai-triage-agent[bot] 576164960f Merge pull request #250 from MervinPraison/claude/issue-240-20260727-0912
feat: surface degraded knowledge search when embedding model unavailable
2026-07-31 12:08:20 +00:00
praisonai-triage-agent[bot] 9ec612b362 Merge pull request #249 from MervinPraison/claude/issue-235-20260727-0910
fix: prevent cp1252 UnicodeEncodeError in dashboard examples
2026-07-31 12:04:29 +00:00
praisonai-triage-agent[bot] 56760f843c Merge pull request #248 from MervinPraison/claude/issue-238-20260727-0912
fix: require explicit opt-in for GATEWAY_AUTH_TOKEN url auth
2026-07-31 12:00:49 +00:00
praisonai-triage-agent[bot] 39123500d5 Merge pull request #214 from MervinPraison/claude/issue-209-20260714-fix
fix: dedupe aiui:prefill-composer listener across chat re-navigations
2026-07-31 11:57:08 +00:00
praisonai-triage-agent[bot] 4098e5da4b Merge pull request #213 from MervinPraison/claude/issue-207-20260714-fix
fix: overview approval polling stacks duplicate click handlers (#207)
2026-07-31 11:53:16 +00:00
MervinPraison b3daa2fcfa Release v0.3.139 2026-07-31 11:52:38 +00:00
praisonai-triage-agent[bot] 7c7c121940 Merge pull request #215 from MervinPraison/claude/issue-211-20260714-work-hub-chat
feat: Work Hub Chat tab sends messages to agent via existing transport
2026-07-31 11:49:54 +00:00
praisonai-triage-agent[bot] c1da3fe0ae Merge pull request #212 from MervinPraison/claude/issue-210-20260714-1010
fix: honest gateway reachability probe on onboarding Screen 1
2026-07-31 11:48:48 +00:00
praisonai-triage-agent[bot]andMervin Praison a44776b18e fix: surface AC-4 opt-in on cross-origin CORS block in gateway probe
The reachability probe used default cors mode, so a cross-origin CORS
block rejected the fetch (landing in the 'network' branch) instead of
producing an opaque response. That made the 'opaque' branch and its
"Continue anyway" checkbox (AC-4) dead code. Now a rejected fetch on a
cross-origin URL maps to 'opaque' (ambiguous: CORS-blocked or down) so
the opt-in checkbox renders, while same-origin rejections remain a
definitive 'network' error.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-31 10:56:40 +00:00
MervinPraison 0e095d73fe fix: unblock FINAL @claude when review bots stay silent
Port PraisonAI review-chain parity: 30-minute required-reviewer timeout,
skip Copilot in scheduled FINAL sweep, and selftests for timeout path.
2026-07-31 11:53:09 +01:00
praisonai-triage-agent[bot]andMervin Praison d9836a955e fix: drop superseded #238 token-auth changes (already landed via #251)
Main's #251/#253/#258 implements the #238 fix with a stricter, more secure
design: AIUI_URL_TOKEN / GATEWAY_AUTH_TOKEN alone are inert; URL-token auth
activates only on explicit opt-in (AIUI_REQUIRE_TOKEN, YAML auth.requireToken,
require_auth). This branch's earlier variant treated AIUI_URL_TOKEN presence
(and YAML auth.urlToken) as an opt-in signal, which forced 401 and broke
test_token_auth_optin.py::test_aiui_url_token_alone_does_not_force_401.

Revert server.py to main's canonical logic and drop the now-conflicting
tests/unit/test_gateway_token_optin.py (its cases are covered by main's
tests/unit/test_token_auth_optin.py).

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 06:34:03 +00:00
praisonai-triage-agent[bot]andMervin Praison 0f986461f9 fix: require explicit opt-in for GATEWAY_AUTH_TOKEN url auth (fixes #238)
GATEWAY_AUTH_TOKEN leaked into an interactive shell no longer silently
enforces 401 on every /api/* route in standalone create_app(). Enforcement
now requires explicit intent via AIUI_URL_TOKEN, AIUI_REQUIRE_TOKEN=1, or
YAML auth.urlToken. Secured gateway deployments keep working.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 06:32:39 +00:00
MervinPraisonandClaude 6ffc84e9ba fix: scope overview approval re-bind to re-rendered subtrees (fixes #207)
refreshApprovals re-rendered only #ov-metrics and #ov-attention but then
called bindEvents on the whole overview root, stacking click/keydown
listeners on unchanged shell nodes (agent rows, omnibar) on every 10s poll.
Scope the re-bind to the two re-rendered subtrees so stale nodes keep a
single listener. paint() still does the full-tree bind on initial render.

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

Co-Authored-By: Claude <[email protected]>
2026-07-30 06:32:21 +00:00
MervinPraisonandClaude d4aa8c2ec4 feat: wire Work Hub Chat tab to agent via shared mini-chat transport (fixes #211)
Add mini-chat.js reusing the existing /api/chat/ws protocol (run_content/
run_completed/run_error) and wire work-hub.js renderChat() to stream real
agent replies instead of only appending a local DOM bubble. Sessions/agents
rebind per card and the WebSocket is torn down on card/tab switch.

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

Co-Authored-By: Claude <[email protected]>
2026-07-30 06:32:14 +00:00
MervinPraisonandClaude c4be709f8d fix: dedupe aiui:prefill-composer listener across chat re-navigations (fixes #209)
Register the Code Studio prefill listener as a module-scope singleton via
ensurePrefillListener() and remove it in cleanup(), preventing duplicate
window handlers from stacking on repeated SPA navigation between /chat and
/code-studio.

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

Co-Authored-By: Claude <[email protected]>
2026-07-30 06:32:06 +00:00
praisonai-triage-agent[bot]andMervin Praison 92adfc6f6e fix: honest gateway reachability probe on onboarding Screen 1 (fixes #210)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-30 06:32:04 +00:00
MervinPraison 90315326f7 Release v0.3.138 2026-07-30 01:56:27 +00:00
MervinPraison 0719c41399 fix: auto-trigger conflict and CI fixes without FINAL review gate
Remove the FINAL @claude prerequisite from merge-conflict and CI-failure
workflows, clear pipeline/blocked:conflict after rebase completion, add
bot-pr-recovery cron, and update gate selftests.
2026-07-29 18:15:42 +01:00
praisonai-triage-agent[bot] d008b6a250 Merge pull request #216 from MervinPraison/claude/issue-208-20260714-i18n-memory
feat: wire i18n strings and per-turn memory search into context ring UI
2026-07-29 14:38:03 +00:00
praisonai-triage-agent[bot]andMervin Praison 05fb59e890 feat: surface degraded knowledge search when embedding model unavailable (fixes #240)
Rebased onto latest main. Reconciled with the overlapping degraded-mode
work already merged from #234:
- Adopt main's canonical _is_embedding_error / _embedding_error naming,
  embedding health dict, and richer /v1/embeddings fallback (503 vs 500).
- Keep _is_embedding_unavailable helper (used by main's test suite).
- Align SimpleKnowledgeManager fallback-test to main's "local" mode.

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

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 13:11:17 +00:00
praisonai-triage-agent[bot]andMervin Praison 8067429e83 fix: prevent cp1252 UnicodeEncodeError in dashboard examples (fixes #235)
Add examples/python/_shared/console.py with safe_print/icon helpers
mirroring the CLI _supports_unicode/_icon pattern, and wire safe_print
into the gateway and channel examples so emoji output degrades to ASCII
on legacy Windows consoles instead of crashing before the server starts.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-29 13:07:27 +00:00
MervinPraisonandClaude 631ae74a29 feat: wire i18n strings and per-turn memory search into context ring UI (fixes #208)
Gap A: chat.js now loads locale strings via /api/i18n and renders ring
tooltip, compaction banner, compacted flash, and memory chip through a
t() helper with English fallback.

Gap B: refreshMemoryChip() posts the last user message to
/api/memory/search and shows per-turn hit count instead of the total
stored memory count from GET /api/memory.

Gap C: role="progressbar" and aria-value* moved to the ring wrapper div;
the send button is now type="button" with a send-only label.

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

Co-Authored-By: Claude <[email protected]>
2026-07-29 13:05:17 +00:00
praisonai-triage-agent[bot] e85f6778dd Merge pull request #258 from MervinPraison/claude/issue-256-20260729-120000
fix: stop full-suite pollution flaking auth timing + health cache tests
2026-07-29 11:39:19 +00:00
praisonai-triage-agent[bot] d6354fade0 Merge pull request #257 from MervinPraison/claude/issue-255-20260729-000000
fix: Windows-safe test_default_sqlite_url (stub HOME/USERPROFILE)
2026-07-29 11:35:43 +00:00
MervinPraisonandClaude b16a5f6056 fix: stop full-suite pollution flaking auth timing + health cache tests (fixes #256)
Reset the global _features registry in the test_server client fixture so a
feature leaked by an earlier crashing test cannot slow /health and flake the
deep-health cache/timing assertions. Make test_timing_attack_resistance
noise-resistant by comparing the median of repeated samples with a warm-up
instead of a single sample, so CPU contention under the full suite no longer
trips the variance threshold.

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

Co-Authored-By: Claude <[email protected]>
2026-07-29 09:28:32 +00:00
MervinPraisonandClaude 6521beb7b2 fix: stub HOME/USERPROFILE in test_default_sqlite_url for Windows (fixes #255)
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-29 09:21:35 +00:00
MervinPraison 9e3384c40a Release v0.3.137 2026-07-29 02:06:56 +00:00
praisonai-triage-agent[bot] e12416e15b Merge pull request #254 from MervinPraison/claude/issue-252-20260728-000000
fix: make five unit tests pass on Windows
2026-07-28 11:38:05 +00:00
MervinPraison 5568b10077 Release v0.3.136 2026-07-28 11:33:51 +00:00
praisonai-triage-agent[bot] 557852b287 Merge pull request #253 from MervinPraison/claude/issue-251-20260728-000000
fix: make URL-token auth opt-in so env token no longer forces 401
2026-07-28 11:30:52 +00:00
MervinPraisonandClaude 652d612d35 fix: make five unit tests pass on Windows (fixes #252)
Resolve cross-platform failures caused by Windows' coarse time.time()
resolution, backslash path separators, and reliance on the grep binary.

- lifecycle: measure hook durations with time.perf_counter() so
  startup_time/shutdown_time are non-zero on Windows' low-res wall clock
- datastore: build the default sqlite URL with Path.as_posix() for a
  consistent forward-slash URL across platforms
- test_audio_hooks: allow last_chunk_at == started_at (clock granularity)
- test_sqlalchemy_datastore: compare against as_posix() paths
- test_unified_naming: replace grep subprocess with a portable Python scan

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

Co-Authored-By: Claude <[email protected]>
2026-07-28 10:17:52 +00:00
MervinPraisonandClaude 1f578a4827 fix: make URL-token auth opt-in so env token no longer forces 401 (fixes #251)
TokenQueryMiddleware previously activated whenever GATEWAY_AUTH_TOKEN or
AIUI_URL_TOKEN was present in the process environment, forcing 401 on all
standalone /api/* routes. A token leaking into a developer shell after a
gateway run broke ad-hoc TestClient scripts (#238, #251).

Activation now requires explicit opt-in: AIUI_REQUIRE_TOKEN, YAML
auth.requireToken, or require_auth=True. Secured deployments keep full
Bearer / query-param / cookie token auth.

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

Co-Authored-By: Claude <[email protected]>
2026-07-28 10:16:03 +00:00
praisonai-triage-agent[bot] 84ebdbc695 Merge pull request #247 from MervinPraison/claude/issue-236-20260727-0911
fix: add UTF-8 encoding to frontend source test reads
2026-07-27 12:23:34 +00:00
praisonai-triage-agent[bot] 182d065524 Merge pull request #246 from MervinPraison/claude/issue-239-20260727-120000
fix: correct tracing integration test paths to /api/traces
2026-07-27 12:18:36 +00:00
praisonai-triage-agent[bot] 132018d123 Merge pull request #245 from MervinPraison/claude/issue-237-20260727-0911
fix: use explicit UTF-8 encoding in CLI integration test fixture
2026-07-27 12:13:41 +00:00
MervinPraison bb85860a33 Release v0.3.135 2026-07-27 12:11:31 +00:00
praisonai-triage-agent[bot] c074d0782c Merge pull request #244 from MervinPraison/claude/issue-234-20260727-fix
feat: configurable embedding model + degraded knowledge search reporting
2026-07-27 12:08:27 +00:00
praisonai-triage-agent[bot] f7e19b9a13 Merge pull request #243 from MervinPraison/claude/issue-233-20260727-0904
fix: correct tracing API test paths (/api/tracing -> /api/traces)
2026-07-27 12:02:58 +00:00
praisonai-triage-agent[bot] 1a91f574b9 Merge pull request #242 from MervinPraison/claude/issue-231-20260727-0857
feat: safe_print for examples to avoid cp1252 UnicodeEncodeError
2026-07-27 11:58:32 +00:00
praisonai-triage-agent[bot] 0c982f4959 Merge pull request #241 from MervinPraison/claude/issue-232-20260727-0900
fix: specify UTF-8 encoding for frontend source reads in tests
2026-07-27 11:53:17 +00:00
MervinPraisonandClaude 0cc7f70bbb fix: correct tracing integration test paths to /api/traces (fixes #239)
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-27 09:14:24 +00:00
praisonai-triage-agent[bot]andpraisonai-triage-agent[bot] 87c9ed09b4 fix: add UTF-8 encoding to frontend source test reads (fixes #236)
Standardize Path.read_text() calls across unit/integration tests to
explicitly use encoding="utf-8". On Windows the default locale is cp1252,
which raises UnicodeDecodeError when reading committed UTF-8 frontend
bundles (em dash, emoji, multi-byte chars), producing false negatives.

Co-authored-by: praisonai-triage-agent[bot] <praisonai-triage-agent[bot]@users.noreply.github.com>
2026-07-27 09:14:23 +00:00
praisonai-triage-agent[bot]andMervin Praison 30c34e7266 fix: use explicit UTF-8 encoding in CLI integration test fixture (fixes #237)
Test fixture wrote YAML/markdown and read JSON without encoding, defaulting
to cp1252 on Windows and breaking UTF-8 reads for the © character. Specify
encoding="utf-8" on all write_text/read_text calls for deterministic
cross-platform behaviour.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:13:28 +00:00
MervinPraisonandClaude 43b9fe7253 feat: configurable embedding model + degraded-mode reporting for knowledge search (fixes #234)
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-27 09:10:15 +00:00
praisonai-triage-agent[bot]andMervin Praison 5b61ece40d fix: correct tracing API test paths /api/tracing to /api/traces (fixes #233)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:05:29 +00:00
praisonai-triage-agent[bot]andMervin Praison 6fd27d0ed7 feat: safe_print for examples to avoid cp1252 UnicodeEncodeError (fixes #231)
Add examples/python/_shared/console.py with safe_print/icon helpers that
degrade emoji to ASCII on legacy Windows code pages (cp1252) instead of
crashing, mirroring the CLI _supports_unicode/_icon pattern. Wire the helper
into the high-severity gateway (16, 17, 18) and channel (20-23) examples so
they start on default Windows PowerShell without PYTHONUTF8.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:04:48 +00:00
praisonai-triage-agent[bot]andMervin Praison 78a8a499c1 fix: specify UTF-8 encoding for frontend source reads in tests (fixes #232)
Standardize all Path.read_text() calls in the test suite to pass
encoding="utf-8" so committed UTF-8 frontend JS/HTML bundles decode
correctly on Windows (cp1252 default locale) instead of raising
UnicodeDecodeError.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-27 09:03:59 +00:00
praisonai-triage-agent[bot]andMervin Praison 4d685af1da fix: correct timeline row selected-highlight CSS selector in /runs
The selected-row highlight targeted .rr-timeline-row.selected but rows
render with class .db-timeline-row, so clicking a timeline row never
visually highlighted it. Align the selector to .db-timeline-row.selected.

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

Co-authored-by: Mervin Praison <[email protected]>
2026-07-16 07:55:06 +00:00
MervinPraisonandClaude a1c7a3c279 feat: add Run Flight Recorder /runs three-pane debugger (fixes #217)
Merges chat turns, trace spans, log lines and errors into one per-session
timeline. Reuses existing APIs only. Adds formatDuration/emptyState/
traceStatusBadge/timelineRow helpers, registers the runs page (Control,
order 22), and deep-links from Traces, Command Center and Work Hub.

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

Co-Authored-By: Claude <[email protected]>
2026-07-16 07:55:06 +00:00
MervinPraison 01a31f7c8b Release v0.3.134 2026-07-16 02:07:47 +00:00
praisonai-triage-agent[bot] fc5ce8a30c Merge pull request #230 from MervinPraison/claude/issue-223-20260715-finops
feat: Cost FinOps Strip on Overview and Chat (STITCH-013)
2026-07-15 16:45:49 +00:00
MervinPraisonandClaude c9985de128 feat: Cost FinOps Strip on Overview and Chat (fixes #223)
Add STITCH-013 ambient spend awareness reusing existing usage, config
and context-stats APIs. New _helpers.js FinOps utilities (MiniDonutSVG,
budget math, CostStrip/BudgetBanner markup); Overview CostStrip +
BudgetBanner with graceful degradation; Chat SessionCostChip + budget
banner updating on run_completed; FinOps config schema section with
cross-field validation; finops.* i18n keys (en/es/fr); unit tests.

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

Co-Authored-By: Claude <[email protected]>
2026-07-15 15:25:36 +00:00
praisonai-triage-agent[bot] c3e330454c Merge pull request #227 from MervinPraison/claude/issue-218-20260715-000000
feat: Skills Studio — pending/diff/history for self_improve skill writes
2026-07-15 15:23:05 +00:00
praisonai-triage-agent[bot] 203b885d6b Merge pull request #226 from MervinPraison/claude/issue-220-20260715-1317
feat: Channel Inbox — unified multi-channel message hub (STITCH-010)
2026-07-15 15:19:10 +00:00
praisonai-triage-agent[bot] 9a543164aa Merge pull request #225 from MervinPraison/claude/issue-219-20260715-1317
feat: Eval Quality Cockpit — regression dashboard (STITCH-009)
2026-07-15 15:13:56 +00:00
praisonai-triage-agent[bot] 8eb9d0a75c Merge pull request #224 from MervinPraison/claude/issue-221-20260715-000000
feat: session fork endpoint for Agent Playground (STITCH-011)
2026-07-15 15:08:36 +00:00
praisonai-triage-agent[bot]andMervin Praison 10f3bbe1ce fix(training): correct agent_id filter, apply dropdown source, and view nav order
- features/training.py: derive agent_id in _summarize_session so the
  /api/training/sessions?agent_id= filter actually matches (was always None).
- training-lab.js: fetch /api/agents/definitions (returns `id`) instead of
  /api/agents (returns `agent_id`) so the apply dropdown carries valid agent
  IDs matching the registry; fall back to agent_id defensively.
- agents.js: set the agent_id URL param before selectPage('training') so the
  Training Lab picks up the filter on initial render.
- tests: add regression test for agent_id session filtering.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:47:40 +00:00
praisonai-triage-agent[bot]andMervin Praison 1170b264ee fix: preserve session in eval debug deep-link before navigating
The debug-run deep link only pushed the /runs?session= URL state in the
traces fallback branch, dropping the session when a runs page exists.
Push the URL state before navigating in both cases so Run Flight Recorder
(STITCH-007) receives session context when it lands.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:43:55 +00:00
praisonai-triage-agent[bot]andMervin Praison f0a6b16626 fix: persist fork lineage metadata on default datastores
The session fork endpoint recorded parent_session_id/agent_id/source via
ds.update_session(metadata=...), but the shipped default stores dropped it:
SDKFileDataStore.update_session only handled title/platform/icon and
JSONFileDataStore had no override at all (base no-op). Fork lineage only
survived on the volatile MemoryDataStore used in tests, silently failing in
production.

- SDKFileDataStore: persist custom session metadata in the sentinel meta
  message and surface it via get_session().
- JSONFileDataStore: add update_session override persisting arbitrary kwargs
  (also fixes title updates being lost).
- Add regression test asserting fork metadata persists on the default stores.

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

Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:43:50 +00:00
praisonai-triage-agent[bot]andMervin Praison c66a33c5d3 feat: add Training Lab UI for praisonai-train sessions (fixes #222)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:26:32 +00:00
MervinPraisonandClaude 6608e17303 feat: add Skills Studio pending/diff/history workflow (fixes #218)
Refactor skills.js into a tabbed Skills Studio (Pending, Installed,
History) that surfaces self_improve skill-write approvals, adds a
side-by-side line diff with raw/preview toggle, and wires approve/deny
to the existing /api/approvals endpoints. Adds diffLines,
renderMarkdownPreview and isSkillApproval helpers, a cross-link from
approvals.js for skill rows, and skills.* i18n keys.

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

Co-Authored-By: Claude <[email protected]>
2026-07-15 13:24:41 +00:00
praisonai-triage-agent[bot]andMervin Praison 91ff46dcb1 feat: add Channel Inbox unified multi-channel message hub (fixes #220)
Track B session-filter implementation: new /inbox three-pane view that
derives threads from channel-backed sessions + chat history, persists
status/assignee via session state, replies through the chat transport,
and deep-links to /chat and /work. Surfaces platform/channel_id in the
sessions list API.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:24:25 +00:00
praisonai-triage-agent[bot]andMervin Praison 732bd123d8 feat: Eval Quality Cockpit regression dashboard (fixes #219)
Refactor the read-only /eval table into a quality cockpit: status strip,
hero metrics (pass rate, avg score, regressions, total cases), per-agent
suite cards with 7-day sparklines and trend arrows, localStorage baseline
compare, in-UI run trigger (POST /api/eval/run), and expandable history
rows that deep-link failed cases to Run Flight Recorder (/runs?session=)
with a /traces fallback. All trend/regression logic is client-derived from
existing endpoints; no backend changes.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-15 13:23:57 +00:00
MervinPraisonandClaude 71931db0c6 feat: add session fork endpoint for Agent Playground (fixes #221)
POST /api/sessions/{id}/fork branches a chat session into a new child,
copying messages up to an optional up_to_index and recording parent
metadata. Backend primitive for the Agent Playground (STITCH-011).

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

Co-Authored-By: Claude <[email protected]>
2026-07-15 13:22:59 +00:00
MervinPraison ffa3060f0b Release v0.3.133 2026-07-15 01:57:26 +00:00
praisonai-triage-agent[bot] 6d194fce1b Merge pull request #205 from MervinPraison/claude/issue-200-20260714-code-studio
feat: Code Studio — Monaco editor with sandbox execute and Send to Agent (STITCH-006)
2026-07-14 09:32:47 +00:00
praisonai-triage-agent[bot] 4ecb6497b5 Merge pull request #206 from MervinPraison/claude/issue-196-20260714-context-ring
feat: composer context token ring, memory chip & compaction banner
2026-07-14 08:53:57 +00:00
praisonai-triage-agent[bot] fbd1310639 Merge pull request #203 from MervinPraison/claude/issue-197-20260714-0719
feat: Unified Work Hub /work (STITCH-003)
2026-07-14 08:49:56 +00:00
praisonai-triage-agent[bot] 198c67528c Merge pull request #202 from MervinPraison/claude/issue-198-20260714-0719
feat: first-run onboarding gate for gateway auth (STITCH-004)
2026-07-14 08:46:48 +00:00
praisonai-triage-agent[bot] 303e6305e6 Merge pull request #201 from MervinPraison/claude/issue-195-20260714-0719
feat: Agent Command Center overview (STITCH-001)
2026-07-14 08:42:58 +00:00
MervinPraisonandClaude 17689c4468 feat: add Code Studio view with sandbox execute and Send to Agent (fixes #200)
Add /code-studio dashboard view: lazy Monaco editor, language picker,
sandbox execution via existing /api/code/* endpoints, output/errors/artifacts
tabs, client-side run history, snippet save, and Send to Agent handoff that
prefills the chat composer via aiui:prefill-composer.

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

Co-Authored-By: Claude <[email protected]>
2026-07-14 08:41:40 +00:00
praisonai-triage-agent[bot] f0d08f1cc2 Merge pull request #204 from MervinPraison/claude/issue-199-20260714-000000
feat: plugin marketplace dashboard page (STITCH-005)
2026-07-14 08:39:29 +00:00
praisonai-triage-agent[bot]andMervin Praison 32d27c20c8 fix: escape server-provided plugin fields in marketplace view (XSS)
Interpolated plugin name/description/id/category/version/permissions into
innerHTML without escaping, unlike sibling views (mcp.js, channels.js,
chat.js) which use an esc() helper. Add the same esc() helper and apply it
for defense-in-depth and convention consistency.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:46:42 +00:00
praisonai-triage-agent[bot]andMervin Praison c52728c9e3 fix: hoist pendingHandled/tryDeepLink above board init in work-hub
Declaring pendingHandled (let) and tryDeepLink after the
createInteractiveBoard call that closes over them was a temporal-dead-zone
hazard. Move them above the board construction and simplify the onOpen
deep-link guard.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:44:56 +00:00
praisonai-triage-agent[bot]andMervin Praison da9d7425b9 fix: apply onboarding gateway token to all dashboard API calls
The first-run onboarding gate stored the gateway bearer token in
sessionStorage but no dashboard data fetch (/api/pages, /ui-config.json,
view modules, /api/health, …) attached it, so protected APIs kept
returning 401 after "Connect" — defeating the feature. Install a
one-time window.fetch wrapper in init() that injects the stored bearer
token on same-origin requests when present, preserving any explicit
Authorization header and remaining a no-op in standalone/no-token mode.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:44:50 +00:00
praisonai-triage-agent[bot]andMervin Praison 0b0dfb6f5f fix: wire 'Chat now' deep-link to existing ?agent= param
The overview dispatched an aiui:select-agent CustomEvent that had no
listener anywhere, so 'Chat now'/'Chat' buttons navigated to the chat
page but never pre-selected the agent (dead deep-link). Replace it with
the established ?agent=<name> URL param that chat.js already reads on
mount (chat.js:771), matching the canonical selectSession pattern.
Pass agent name (option value) instead of id so the selector matches.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:43:15 +00:00
MervinPraisonandClaude b84b9d3ee7 feat: composer context token ring, memory chip, compaction banner (fixes #196)
Add a server-driven context budget indicator to the chat composer:
- GET /api/chat/context-stats returns a char-based token estimate with a
  deterministic breakdown (system/tools/messages/memory).
- Token ring wraps the send button with healthy/warning/critical/over
  states, dashed arc for estimates, and a breakdown tooltip.
- Compaction banner surfaces at >=85% usage; a memory chip shows retrieved
  memory count per turn and opens the existing memory panel.
- Ring refreshes on run completion, WS context_update/context_compacted
  events, and a 5s poll fallback.
- i18n keys added for en/es/fr.

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

Co-Authored-By: Claude <[email protected]>
2026-07-14 07:27:36 +00:00
MervinPraisonandClaude 74260cd68a feat: add plugin marketplace dashboard page (fixes #199)
Add a /marketplace dashboard view that browses, inspects permissions,
installs, and uninstalls plugins via the existing features/marketplace.py
backend. Registers the view in dashboard.js BUILTIN_VIEWS and adds the
page entry (Agent group) with the /api/marketplace/plugins endpoint.

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

Co-Authored-By: Claude <[email protected]>
2026-07-14 07:26:24 +00:00
praisonai-triage-agent[bot]andMervin Praison 00bbdd29a6 feat: add Unified Work Hub /work three-pane surface (fixes #197)
Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:25:23 +00:00
praisonai-triage-agent[bot]andMervin Praison b3c62a9cc0 feat: first-run onboarding gate for gateway auth (fixes #198)
Add a guided 4-step onboarding overlay shown on first visit when the
dashboard runs in gateway mode and the user is unauthenticated,
replacing the raw HTTP 401 experience. The gate runs in dashboard.js
init() before buildDashboard() and skips for standalone/authenticated
users and when the "don't show again" flag is set.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:25:00 +00:00
praisonai-triage-agent[bot]andMervin Praison 7998b8ccc0 feat: Agent Command Center overview with live agents, approvals, usage (fixes #195)
Replace the single-endpoint Overview with a mission-control home that fetches
9 APIs in parallel (Promise.allSettled): 6 live metric cards with sparklines,
an active-agents table with a detail drawer, a priority-sorted needs-attention
feed with inline approve/deny, a recent-activity timeline, and an omnibar CTA
that opens the existing Ctrl+K command palette. Polling pauses on hidden tabs
and intervals are torn down on cleanup. All API strings are HTML-escaped.

Adds reusable metricCard, sparklineSVG, esc and timeAgo helpers to _helpers.js.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-14 07:24:15 +00:00
MervinPraison 2ebb56f609 Release v0.3.132 2026-07-14 02:00:30 +00:00
praisonai-triage-agent[bot] 6725a5bdf7 Merge pull request #194 from MervinPraison/claude/issue-191-20260713-0819
fix: honor aiui run --port for gateway examples that delegate to async main()
2026-07-13 10:12:12 +00:00
MervinPraison f1f953be76 Release v0.3.131 2026-07-13 10:08:48 +00:00
praisonai-triage-agent[bot] ee994b586d Merge pull request #193 from MervinPraison/claude/issue-192-20260713-120000
fix: isolate OPENAI_API_KEY in realtime lifecycle test
2026-07-13 10:04:40 +00:00
praisonai-triage-agent[bot]andMervin Praison 44428e5caf fix: propagate --port/--host to gateway main() delegation (fixes #191)
Set PORT/HOST env before delegating to a user-defined async main() so
gateway examples that read os.getenv("PORT") honor the CLI --port flag.
Explicit env set by the user takes precedence over the CLI flag.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-13 08:25:16 +00:00
MervinPraisonandClaude 1748d6d023 fix: isolate OPENAI_API_KEY in realtime session lifecycle test (fixes #192)
🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2026-07-13 08:21:25 +00:00
MervinPraison a45c3af006 Release v0.3.130 2026-07-10 10:49:34 +00:00
praisonai-triage-agent[bot] b54d94dd56 Merge pull request #190 from MervinPraison/claude/issue-189-20260710-0829
feat: restore Channels dashboard Add/Delete/Test CRUD UI
2026-07-10 10:46:59 +00:00
praisonai-triage-agent[bot]andMervin Praison d9e8b12628 feat: restore Channels dashboard Add/Delete/Test CRUD UI (fixes #189)
Restore the + Add Channel modal, per-platform credential fields, setup
hints, and card actions (Enable/Disable, Restart, Test, Delete) that were
removed in the 3961508 refactor. Aligned with #176 secret policy (env
references, no plaintext prefill, inline 400 errors surfaced) and #172
dropdown contrast fix (.db-form-select). Adds POST /api/channels preset to
the API Explorer and neutralizes the legacy read-only plugin so it no
longer clobbers the managed view.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-10 08:34:43 +00:00
MervinPraison 2fb299a454 Release v0.3.129 2026-07-09 17:05:28 +00:00
praisonai-triage-agent[bot] e288fca9ca Merge pull request #184 from MervinPraison/claude/issue-174-20260708-0849
fix: dashboard generator emits main before shellHeader insertBefore (#174)
2026-07-09 16:53:45 +00:00
praisonai-triage-agent[bot] f3dd9b218d Merge pull request #182 from MervinPraison/claude/issue-177-20260708-120000
feat: surface user-visible errors for offline chat send
2026-07-09 16:51:10 +00:00
praisonai-triage-agent[bot] 949a1862da Merge pull request #181 from MervinPraison/claude/issue-178-20260708-120000
fix: expose Ctrl+K command palette globally + guard init idempotency
2026-07-09 16:47:38 +00:00
praisonai-triage-agent[bot]andMervin Praison 7167546900 test: align shell-error assertions with showDashboardInitError after rebase
The rebase onto main kept main's showDashboardInitError() helper, which
supersedes this PR's showShellError() and renders the same .db-error
banner with role=alert. Update the RC-2 assertions to match the surviving
helper name; UX guarantee (visible shell error on missing #db-main-content)
is unchanged.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-09 16:10:20 +00:00
MervinPraisonandClaude e029f6e063 feat: surface user-visible errors for offline chat send (fixes #177)
Add defensive shell error UI in dashboard.js selectPage, offline-aware
HTTP fallback messaging with toast, role=alert on system error bubbles,
and a try/catch guard around ws.send in chat.js sendMessage.

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

Co-Authored-By: Claude <[email protected]>
2026-07-09 17:06:25 +01:00
praisonai-triage-agent[bot] 32e8552840 Merge pull request #173 from MervinPraison/claude/issue-172-20260630-120000
fix: dark-theme dropdown contrast and sidebar header overlap
2026-07-09 16:04:43 +00:00
Mervin Praison e31df90d0e Merge pull request #179 from MervinPraison/claude/issue-175-20260708-000000
fix: surface selectPage error when dashboard shell incomplete
2026-07-09 17:04:40 +01:00
praisonai-triage-agent[bot] 58c66b65e5 Merge pull request #180 from MervinPraison/claude/issue-176-20260708-120000
fix: redact channel secrets in all API responses
2026-07-09 16:04:10 +00:00
praisonai-triage-agent[bot]andMervin Praison f0c298802b fix: emit main before shellHeader insertBefore in dashboard generator (fixes #174)
The dashboard.js generator emitted root.insertBefore(shellHeader, main)
before root.appendChild(main), so regenerating the bundle re-introduced
the #166/#174 insertBefore NotFoundError. Reorder the generator to append
main first, and lock it with a source-parsing regression test.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-09 17:00:21 +01:00
praisonai-triage-agent[bot]andMervin Praison 45a5f0cd2d test: align session-search Ctrl+K test with command-palette ownership
The Ctrl+K/Cmd+K binding moved to initCommandPalette; initSessionSearch
now only owns Escape-to-close. Update test_ctrl_k_keydown_handler_present
to assert the current architecture instead of the outdated contract.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-09 17:00:18 +01:00
MervinPraisonandClaude 1b0e1646c9 fix: expose command palette globally and guard init idempotency (fixes #178)
BQA-002 (insertBefore) and the base command palette are already present in
the shipped dashboard bundle. This closes the remaining acceptance gaps:
openCommandPalette is now reachable in the global scope
(typeof openCommandPalette === 'function') and initCommandPalette no longer
double-registers its keydown handler on HMR / full reload.

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

Co-Authored-By: Claude <[email protected]>
2026-07-09 17:00:18 +01:00
praisonai-triage-agent[bot]andpraisonai-triage-agent[bot] 2fe1a83c9a fix(ci): guard find_spec so missing praisonai parent pkg skips instead of erroring
find_spec("praisonai.jobs") raises ModuleNotFoundError (not returns None)
when the parent 'praisonai' package is absent, aborting collection of the
entire tests/unit suite in CI. Wrap in a helper that treats the missing
parent as unavailable so the SDK test skips cleanly.

Co-authored-by: praisonai-triage-agent[bot] <praisonai-triage-agent[bot]@users.noreply.github.com>
2026-07-09 17:00:15 +01:00
praisonai-triage-agent[bot]andMervin Praison 971033b905 fix(channels): align write-path secret validation with read-path redaction
_validate_config_security used the narrow exact-match SECRET_FIELD_PATTERNS
while _redact_config_secrets was hardened to also catch *_token/*_key/*_secret/
*_password suffix keys. This closed the read leak but still let inline
app_token/signing_secret/client_secret values be stored on write. Route both
paths through the shared _is_secret_key helper so suffix secrets are rejected
at write time too, and add regression tests.

Co-authored-by: Mervin Praison <[email protected]>
2026-07-09 17:00:15 +01:00
MervinPraisonandClaude 0626d0bb96 fix: redact channel secrets in all API responses (fixes #176)
GET /api/channels and related handlers serialized the in-memory _channels
dict verbatim, exposing config.bot_token and other secrets. Harden
_redact_config_secrets to cover *_token/*_key/*_secret/*_password suffix
keys (app_token, signing_secret, client_secret) and emit a <key>_set flag,
and redact the previously-unredacted _toggle response. Write path still
accepts and uses real tokens for bot startup.

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

Co-Authored-By: Claude <[email protected]>
2026-07-09 17:00:15 +01:00
MervinPraisonandClaude 581df433ed fix: surface selectPage error when dashboard shell incomplete (fixes #175)
Replace the silent `if (!main || !page) return;` early return in
selectPage() with explicit guards that log a console error and, when
#db-main-content is absent, render a visible db-error banner via the new
showDashboardInitError helper.

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

Co-Authored-By: Claude <[email protected]>
2026-07-09 17:00:13 +01:00
MervinPraisonandClaude bead6e4542 fix: dark-theme dropdown contrast and sidebar header overlap (fixes #172)
Native <select> option popups inherited the dashboard light foreground
while the browser painted a white system surface, producing unreadable
white-on-white platform labels. Add explicit dark-surface/light-text
styling for .db-form-select option and any dashboard select option, plus
an accent highlight for the checked option.

Harden the sidebar header so a long brand title truncates with an
ellipsis and reserves space for the toggle, preventing text overlap.

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

Co-Authored-By: Claude <[email protected]>
2026-07-09 17:00:11 +01:00
MervinPraison d0c8e060ff Release v0.3.128 2026-07-09 15:24:52 +00:00
Mervin Praison cdd6b21d3b Merge pull request #188 from MervinPraison/fix/merge-gate-stash-config
fix(merge-gate): stash gate-config.js with merge-gate.js
2026-07-09 16:21:34 +01:00
praisonai-triage-agent[bot]andMervin Praison b5f35214ef fix(ci): sync version and update stale registry/session-search tests
Pre-existing failures on main unrelated to the merge-gate workflow diff:
- sync __version__.py to 0.3.127 to match pyproject.toml
- i18n graduated to IMPLEMENTED (0.5.0); update feature-registry tests
- Ctrl+K binding is owned by initCommandPalette; assert the UX contract
  (Ctrl+K routes to session search) instead of the old implementation detail

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

Co-authored-by: Mervin Praison <[email protected]>
2026-07-09 15:03:46 +00:00
MervinPraison 2f73a94808 fix(merge-gate): stash gate-config.js with merge-gate.js 2026-07-09 15:57:21 +01:00
Mervin Praison 611c06f31b Merge pull request #187 from MervinPraison/fix/ci-sdk-job-store-import
fix(ci): skip SDK job store test when praisonai missing
2026-07-09 14:37:21 +01:00
MervinPraison 7f41bcbd9c fix(ci): skip SDK job store test when praisonai missing
find_spec(\"praisonai.jobs\") raises ModuleNotFoundError when the parent
package is absent, aborting pytest collection. Catch that and skip.
Also add claude-code-action and restore it after PR checkout for merge gate.
2026-07-09 14:30:26 +01:00
Mervin Praison f47b9f3824 Merge pull request #186 from MervinPraison/fix/ruff-channels-whitespace
fix(ci): clear ruff whitespace blocking main CI
2026-07-09 10:03:50 +01:00
MervinPraison 0e1a90b9f8 fix(ci): clear ruff W291/W293 whitespace in channels.py
Unblocks main and all open PRs blocked on python lint in CI.
2026-07-09 10:00:20 +01:00
Mervin Praison f86baee258 Merge pull request #185 from MervinPraison/infra/stale-final-recovery
infra: stale-FINAL recovery for open PRs
2026-07-08 10:56:33 +01:00
MervinPraison 69e469e71f infra: add stale-FINAL recovery for open PRs
Port claude-review-recovery and scheduled post-missing-claude-final from
PraisonAI, with allowStaleRepost so FINAL can be re-posted after new commits.
Remove duplicate bot-pr-trigger-reviews job.
2026-07-08 10:45:46 +01:00
Mervin Praison 1b2103e3a8 Merge pull request #183 from MervinPraison/infra/gate-setup
infra: merge gate, release gate, and pipeline automation
2026-07-08 09:48:11 +01:00
MervinPraison 88307cf5b0 infra: add merge gate, release gate, and pipeline automation
Port PraisonAI gate scripts with gate-config.js for PraisonAIUI paths,
single-package release preflight, pipeline label sync, Opus merge gate,
CI failure Claude trigger, pypi-auto patch releases, and review-chain hooks.
2026-07-08 09:36:56 +01:00
MervinPraison 140dd3a443 fix(version): update aiui to version 0.3.127 in project files
Updated the version in pyproject.toml and uv.lock to reflect the latest release.
2026-07-05 06:21:52 +01:00
MervinPraison 20b29caae3 chore(version): update aiui version to 0.3.126
Bumped the version in pyproject.toml and uv.lock to reflect the latest release.
2026-06-29 10:06:23 +01:00
MervinPraison d6cff26261 feat(version): update aiui version to 0.3.125
Incremented the version of the aiui project to 0.3.125 in both
pyproject.toml and uv.lock files to reflect the latest release.
2026-06-29 10:05:57 +01:00
Mervin Praison 7018271836 Merge pull request #171 from MervinPraison/claude/issue-170-20260628-120000
feat: world-class kanban board — dense cards, editable drawer, debounced live updates
2026-06-29 10:05:26 +01:00
Mervin Praison 61e5fd04ed Merge pull request #169 from MervinPraison/claude/issue-167-20260626-120000
fix: harden channel auto-start lifecycle and running state
2026-06-29 10:04:59 +01:00
Mervin Praison 80deeb451a Merge pull request #168 from MervinPraison/claude/issue-166-20260626-000000
fix: dashboard buildDashboard insertBefore NotFoundError (#166)
2026-06-29 10:04:46 +01:00
MervinPraisonandClaude 9726411010 feat: enrich kanban cards, editable drawer, debounced live updates (fixes #170)
Gap 1: card DTO now carries tenant, created_at, comment_count and child
progress; cardElement renders dense chrome (checkbox, status dot, id,
priority badge, tenant chip, assignee, age, comment count, progress pill).

Gap 2: new POST /api/kanban/tasks/{id}/comments route plus add_comment on
the store protocol; drawer is now editable (title/assignee/priority),
markdown-rendered (XSS-safe), shows a comment thread with Enter-to-submit
and run/event history rows.

Gap 3: SSE consumer refetches on a 300ms debounce, the open drawer
live-refreshes on events for its task, and destructive moves/delete prompt
for confirmation.

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

Co-Authored-By: Claude <[email protected]>
2026-06-28 04:23:35 +00:00
MervinPraisonandClaude 7cb20bca32 fix: harden channel auto-start lifecycle and running state (fixes #167)
Gateway _channel_tasks may be a dict or a list depending on SDK version;
calling .append() on a dict raised 'dict' object has no attribute 'append'
during auto-start. Register defensively for both shapes and never let a
gateway bookkeeping failure abort an already-started bot.

Also force running=False whenever start_error is set (in _sync_running_status
and the auto-start failure paths) so the API no longer reports running=true
alongside an error, and log full tracebacks via logger.exception.

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

Co-Authored-By: Claude <[email protected]>
2026-06-26 06:20:46 +00:00
MervinPraisonandClaude 11898f2c7d fix: append main before insertBefore in dashboard buildDashboard (fixes #166)
buildDashboard() called root.insertBefore(shellHeader, main) before main was
a child of root, throwing NotFoundError and aborting the dashboard plugin
init, which blocked Ctrl+K and the browser chat input. Append main to root
first so it is a valid reference node for the guarded header insert.

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

Co-Authored-By: Claude <[email protected]>
2026-06-26 06:19:37 +00:00
MervinPraisonandCursor 0b62e7dcec feat: add PyPI Release workflow for aiui package
Manual workflow_dispatch release matching PraisonAI: patch bump,
uv publish, PyPI wait, commit, tag, and GitHub release. Update
instruction.md with PraisonAIUI publish steps.

Co-authored-by: Cursor <[email protected]>
2026-06-25 07:48:12 +01:00
MervinPraisonandCursor fdef44b303 feat: add SDK/product value gate to Claude FINAL review prompts
Centralise PraisonAIUI scope and phase text in workflow env vars and
require Claude to evaluate genuine UI value, correct layering vs
praisonaiagents, and reject scope creep before approving PRs.

Co-authored-by: Cursor <[email protected]>
2026-06-25 07:47:13 +01:00
Mervin Praison 596bb2684c Merge pull request #164 from MervinPraison/claude/issue-162-20260625-0601
fix: sync __version__.py to 0.3.124 (fixes #162)
2026-06-25 07:46:27 +01:00
Mervin Praison 047b86b89f Merge pull request #165 from MervinPraison/claude/issue-163-20260625-0601
feat: parallelize legacy /health and add short-TTL cache
2026-06-25 07:46:10 +01:00
praisonai-triage-agent[bot]andpraisonai-triage-agent[bot] f60f81e086 feat: parallelize legacy /health and add short-TTL cache (fixes #163)
Run provider.health() concurrently with feature checks under a single
bounded gather instead of awaiting the provider first, and cache the deep
health payload for a short TTL so repeat probes stay fast.

Co-authored-by: praisonai-triage-agent[bot] <praisonai-triage-agent[bot]@users.noreply.github.com>
2026-06-25 06:04:59 +00:00
praisonai-triage-agent[bot]andMervin Praison 62d20465b5 fix: sync __version__.py to 0.3.124 (fixes #162)
Co-authored-by: Mervin Praison <[email protected]>
2026-06-25 06:02:41 +00:00
MervinPraison c2f8af6ad0 chore(release): bump version to 0.3.124
Updated version in pyproject.toml and uv.lock to reflect new release.
2026-06-24 23:50:34 +01:00
Mervin Praison 9bb312c8c4 Merge pull request #160 from MervinPraison/claude/issue-155-20260624-120000
feat: Ctrl+K session search in dashboard style (C-01, #155)
2026-06-24 23:50:10 +01:00
MervinPraison d07e41e69b fix(version): update aiui version to 0.3.123
Updated the version in pyproject.toml and uv.lock to reflect the new release.
2026-06-24 23:49:50 +01:00
MervinPraisonandClaude 043aa5c711 feat: port Ctrl+K session search to dashboard style (fixes #155)
Completes C-01 parity for the dashboard presentation plane. PR #145 shipped
SessionSearch in React layouts only, so the primary ops example
(15-dashboard-test, style="dashboard") never mounted React and Ctrl+K did
nothing. This adds a vanilla-JS command palette to dashboard.js (Ctrl+K /
Cmd+K toggle, debounced filter, arrow-key nav, Enter/click select, Esc close)
backed by GET /sessions, and wires chat.js to load the chosen session via an
aiui:session-select event.

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

Co-Authored-By: Claude <[email protected]>
2026-06-24 22:23:18 +00:00
MervinPraisonandCursor 4c5dadd255 fix: dedupe merge-conflict Claude triggers on main push bursts
Main pushes bypassed the 12h cooldown and concurrent merge runs each
posted @claude for every open DIRTY PR. Apply cooldown always, skip when
claude-conflict-pending label exists, cancel stale scans, and sync fork
handling plus FINAL review gate from PraisonAI.

Co-authored-by: Cursor <[email protected]>
2026-06-24 23:22:54 +01:00
Mervin Praison 86a6018c81 Merge pull request #156 from MervinPraison/claude/issue-153-20260624-0952
fix: sync __version__.py to 0.3.122 (fixes #153)
2026-06-24 23:18:29 +01:00
Mervin Praison 5f37843e3d Merge pull request #157 from MervinPraison/claude/issue-150-20260624-000000
fix(compiler): write all build output as UTF-8 (Windows cp1252)
2026-06-24 23:18:20 +01:00
Mervin Praison 4e2e14699c Merge pull request #158 from MervinPraison/claude/issue-151-20260624-000000
feat: implement /api/provider/health JSON route + guard /api/* catch-all
2026-06-24 23:18:06 +01:00
Mervin Praison 5e512d28da Merge pull request #159 from MervinPraison/claude/issue-152-20260624-0952
feat: parallelize legacy /health and migrate consumers to fast probes
2026-06-24 23:17:44 +01:00
Mervin Praison 420f3776d8 Merge pull request #161 from MervinPraison/claude/issue-154-20260624-0952
feat: MCP manager view + Ctrl+K command palette (B-08, B-02)
2026-06-24 23:17:08 +01:00
praisonai-triage-agent[bot]andMervin Praison 6afb282d76 feat: add MCP manager view and Ctrl+K command palette to dashboard (fixes #154)
Implements B-08 (MCP manager) and B-02 (command palette) from the OpenClaw
Control UI parity umbrella. MCP view lists/connects/disconnects servers via
the existing /api/mcp/* routes; command palette navigates pages via Ctrl+K.

Co-authored-by: Mervin Praison <[email protected]>
2026-06-24 09:58:56 +00:00
praisonai-triage-agent[bot]andMervin Praison 67137d4ba4 feat: parallelize legacy /health and migrate consumers to fast probes (fixes #152)
Legacy /health ran sequential per-feature health checks (~2.8s with 42
features). Parallelize with asyncio.gather + 0.5s per-feature timeout
matching /health/ready, and short-circuit ?deep=false to liveness.
Migrate CLI health-check/doctor status to /health/live and provider
status to /health/ready?deep=false. Update K8s/Docker probe docs to
/health/live.

Co-authored-by: Mervin Praison <[email protected]>
2026-06-24 09:57:46 +00:00
MervinPraisonandClaude faec8047b4 feat: implement /api/provider/health JSON route and guard /api/* catch-all (fixes #151)
Register a dedicated GET /api/provider/health handler before the SPA
catch-all so API clients receive JSON instead of dashboard HTML. Unmatched
/api/* paths now return a JSON 404 in both the static-mount fallback and the
path:path catch-all. Docs updated to match the implementation schema.

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

Co-Authored-By: Claude <[email protected]>
2026-06-24 09:57:43 +00:00
MervinPraisonandClaude 0d3baebaf3 fix(compiler): write all text output as UTF-8 (fixes #150)
Path.write_text/open default to the locale encoding (cp1252 on
Windows), causing UnicodeEncodeError when compiled HTML/JSON/CSS
contains non-ASCII content such as the U+2728 sparkle from docs.
Add explicit encoding="utf-8" to every text write in the build
and config pipeline.

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

Co-Authored-By: Claude <[email protected]>
2026-06-24 09:57:42 +00:00
praisonai-triage-agent[bot]andMervin Praison fe1bcd5e28 fix: sync __version__.py to 0.3.122 (fixes #153)
Co-authored-by: Mervin Praison <[email protected]>
2026-06-24 09:54:25 +00:00
MervinPraison ee62c7b908 feat(release): bump version to 0.3.122 and update dependencies
Updated the project version in `pyproject.toml` and `uv.lock`.
Changed dependency versions for `praisonai` and `praisonaiagents`
to their latest compatible versions, ensuring better stability and features.
2026-06-24 09:48:15 +01:00
Mervin Praison da9ff14884 Merge pull request #145 from MervinPraison/claude/issue-128-20260617-0955
feat: add session search palette with Ctrl+K shortcut
2026-06-24 09:47:14 +01:00
MervinPraison c55303684a chore: remove merge conflict CI test marker 2026-06-24 09:04:52 +01:00
MervinPraison d516d9e538 fix(ci): use GH_TOKEN PAT so @claude comment triggers claude.yml 2026-06-24 09:02:27 +01:00
MervinPraison a8d7e4598c fix(ci): grant pull-requests write for merge-conflict Claude comments 2026-06-24 09:00:40 +01:00
MervinPraison dcef9ff502 test: main-side merge conflict marker for CI automation test 2026-06-24 08:59:59 +01:00
MervinPraison fd038d054e ci: auto-trigger Claude on merge conflicts across PRs
Add merge-conflict-claude workflow and conflict rebase prompt with GraphQL merge_state detection in claude.yml.
2026-06-24 08:58:36 +01:00
Mervin Praison a2b941dd24 Merge pull request #146 from MervinPraison/claude/issue-132-20260623-0941
fix: Windows CLI UnicodeEncodeError for Rich output (fixes #132)
2026-06-23 12:33:09 +01:00
Mervin Praison 6d9d0727f2 Merge pull request #147 from MervinPraison/claude/issue-133-20260623-0941
fix: explicit UTF-8 encoding for text file reads on Windows (fixes #133)
2026-06-23 12:32:57 +01:00
Mervin Praison 1f887bd142 Merge pull request #148 from MervinPraison/claude/issue-134-20260623-0941
fix: doctor Gateway check uses /api/provider endpoint (fixes #134)
2026-06-23 12:32:50 +01:00
praisonai-triage-agent[bot]andMervin Praison 6facab2366 fix: use dynamic _icon() fallback for Windows-safe Rich output
Address Gemini reviewer feedback on the inconsistent hard-coded ASCII
replacements. Introduce _supports_unicode()/_icon() helpers that keep the
rich emoji UI on UTF-aware terminals (macOS/Linux/Windows Terminal) and
degrade to ASCII only on legacy code pages (cp1252/cp437), so output is
both crash-safe and free of UX regressions.

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 11:08:41 +00:00
praisonai-triage-agent[bot]andMervin Praison e9d5cff7db fix: doctor Gateway extractor reads flat /api/provider JSON (fixes #134)
The /api/provider endpoint flattens provider.health() into the top-level
response via info.update(health_data), so there is no nested "health"
object. The previous extractor read data.get("health") which was always
None, forcing status to "unknown" and the Gateway check to always "warn".
Read status/provider directly from the top-level dict.

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

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 11:06:15 +00:00
praisonai-triage-agent[bot]andMervin Praison ff54833c84 fix: address review feedback on session search palette
- useSessionSearch: add `enabled` param so global Ctrl+K is only
  intercepted when the palette is rendered; case-insensitive key check
- ChatLayout: only enable the shortcut in fullscreen mode
- AgentUILayout: pass currentSessionId/onSessionChange to ChatArea so
  session selection is functional
- SessionSearch: guard async fetch with an active flag, hoist date
  objects out of the reduce loop, use a div for the loading state
  (CommandEmpty only renders post-filter)
- tests: patch async _datastore with AsyncMock and build the app via
  create_app() so the /sessions endpoint tests actually run

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

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 11:04:04 +00:00
MervinPraison 193dfcdef5 chore(ci): pin Claude Actions model to claude-opus-4-8 2026-06-23 11:39:36 +01:00
Mervin Praison 56181c8532 Merge pull request #130 from MervinPraison/claude/issue-127-20260617-0955
feat: implement exec approval modal (B-01) for OpenClaw UI parity
2026-06-23 11:39:10 +01:00
Mervin Praison 69461ebef3 Merge pull request #131 from MervinPraison/claude/issue-126-20260617
feat: wire i18n config to frontend runtime
2026-06-23 11:39:05 +01:00
Mervin Praison 7cc2031477 Merge pull request #143 from MervinPraison/claude/issue-137-fix-popstate
feat: fix browser Back/Forward navigation in docs SPA
2026-06-23 11:39:00 +01:00
Mervin Praison 9624f0b8df Merge pull request #144 from MervinPraison/claude/issue-139-20260623
feat: standardize health status checking to accept both 'ok' and 'healthy'
2026-06-23 11:38:55 +01:00
Mervin Praison 81aa5bf1e4 Merge pull request #141 from MervinPraison/claude/issue-136-health-alias
feat: add 'health' alias for 'health-check' command
2026-06-23 11:38:49 +01:00
Mervin Praison ec5d3087ab Merge pull request #142 from MervinPraison/claude/issue-135-health-performance
feat: optimize health endpoints for performance (fixes #135)
2026-06-23 11:38:43 +01:00
Mervin Praison d0e02dfd6d Merge pull request #129 from MervinPraison/claude/issue-125-remove-deprecated-dashboard
feat: remove deprecated 12-agent-dashboard example (XSS vulnerability)
2026-06-23 11:38:38 +01:00
Mervin Praison 3ad900a293 Merge pull request #140 from MervinPraison/claude/issue-138-version-sync
feat: sync package version from 0.3.114 to 0.3.121 (fixes #138)
2026-06-23 11:38:29 +01:00
praisonai-triage-agent[bot]andMervin Praison 963735699c refactor: eliminate code duplication in App.tsx navigation logic
- Extract findNavItemByPath as a reusable helper function
- Remove duplicate findItem function definitions
- Use consistent updateSEO function in both handleItemClick and popstate handler
- Move updateSEO function definition before its usage to fix reference order

This improves code maintainability by reducing duplication and ensuring
consistent SEO update behavior across all navigation paths.

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 10:16:56 +00:00
praisonai-triage-agent[bot]andMervin Praison e6e4c5a3e8 fix: extend health status standardization to features commands and test_runner
- Updated features list and features status commands to use is_success_status utility
- Updated test_runner health check to accept both 'ok' and 'healthy' statuses
- Added comprehensive unit tests for features commands with both status values
- Ensures consistent health status handling across entire CLI

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 10:16:09 +00:00
MervinPraison 2b9e78ea50 feat: standardize health status checking to accept both 'ok' and 'healthy' (fixes #139)
- Add health_utils.py with is_success_status() helper function
- Update CLI health-check command to treat both 'ok' and 'healthy' as success
- Update doctor command health extractor to use shared helper
- Update provider status command to use shared helper
- Add comprehensive unit tests for both status strings
- Document health status values in API documentation

The system now consistently accepts both 'ok' and 'healthy' as success
statuses, eliminating false alarms in CLI and doctor commands while
maintaining compatibility with existing dashboard behavior.
2026-06-23 09:51:59 +00:00
MervinPraisonandClaude de6d655250 feat: fix browser Back/Forward navigation in docs SPA (fixes #137)
- Fix popstate event handler to properly update route state when browser Back/Forward buttons are used
- Improve title template handling to support single %s placeholder in SEO config
- Add comprehensive tests for frontend navigation functionality
- Rebuild and update frontend bundle with the fixes

The popstate handler now correctly:
- Finds and sets the matching nav item based on URL path
- Updates both selectedItem and activeItemPath state
- Updates the document title using SEO template
- Handles root path navigation

🤖 Generated with Claude Code

Co-Authored-By: Claude <[email protected]>
2026-06-23 09:51:08 +00:00
MervinPraisonandClaude d9e1f9497d feat: optimize health endpoints for performance (fixes #135)
- Add /health/live for fast liveness checks (<100ms)
- Add /health/ready with parallel feature health checks (timeout: 500ms)
- Implement caching for /api/health endpoint (30s TTL)
- Maintain backward compatibility with existing /health endpoint
- Add comprehensive unit tests for all health endpoints
- Document deployment configurations for K8s, Docker, AWS

Addresses performance issue where /health was taking ~5s due to
sequential feature health checks. New endpoints provide:
- Liveness: <500ms p95 (typically <100ms)
- Readiness: <1s with parallel execution
- Cached: <50ms after first request

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

Co-Authored-By: Claude <[email protected]>
2026-06-23 09:50:00 +00:00
praisonai-triage-agent[bot]andMervin Praison 5c3b93f452 fix: add explicit UTF-8 encoding to all text file reads for Windows compatibility
- Add encoding="utf-8" to all Path.read_text() calls
- Add encoding="utf-8" to all open() calls for text files
- Fixes UnicodeDecodeError on Windows where default encoding is cp1252
- Affects CLI commands, compiler, config store, and various features

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 09:48:31 +00:00
MervinPraisonandClaude 1e81b32f1d feat: add 'health' alias for 'health-check' command (fixes #136)
- Register 'health' as an alias for 'health-check' to support both command names
- Update documentation to use canonical 'health-check' with notes about 'health' alias
- Add tests to verify both commands work correctly

This ensures backward compatibility for users who expect 'aiui health' to work
while maintaining 'health-check' as the canonical command name.

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

Co-Authored-By: Claude <[email protected]>
2026-06-23 09:47:46 +00:00
MervinPraisonandClaude 862f0c4e5e feat: sync package version from 0.3.114 to 0.3.121 (fixes #138)
- Updated __version__.py to match pyproject.toml (0.3.121)
- Added unit test to enforce version consistency
- Ensures CLI, imports, and package metadata report same version

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

Co-Authored-By: Claude <[email protected]>
2026-06-23 09:46:36 +00:00
praisonai-triage-agent[bot]andMervin Praison 27298ebfb2 fix: Windows CLI crashes with UnicodeEncodeError (fixes #132)
- Add Windows UTF-8 reconfiguration at module load
- Replace Unicode symbols with ASCII fallbacks in CLI output
- Update status icons to use [PASS]/[WARN]/[FAIL] instead of emojis
- Replace Unicode arrows and borders with ASCII characters
- Add comprehensive unit tests for Windows encoding

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 09:46:30 +00:00
praisonai-triage-agent[bot]andMervin Praison 33391d6775 fix: update doctor Gateway check to use existing /api/provider endpoint (fixes #134)
The doctor Gateway Status check was calling /api/provider/health which doesn't exist,
causing it to always show HTTP 404. Updated to use the existing /api/provider endpoint
and extract health data from the nested health object.

Co-authored-by: Mervin Praison <[email protected]>
2026-06-23 09:45:23 +00:00
praisonai-triage-agent[bot]andMervin Praison e1bb77ff1f fix(security): add input validation and XSS protection to i18n
- Add regex escaping in LocaleProvider to prevent regex injection
- Add locale format validation (e.g., 'en', 'en-US')
- Add key format validation for translation keys
- Pre-compile regex patterns for better performance
- Add AbortController to handle race conditions
- Add loading state to context for better UX

Co-authored-by: Mervin Praison <[email protected]>
2026-06-17 10:29:41 +00:00
praisonai-triage-agent[bot]andMervin Praison 4fe5667e06 fix: address architecture review findings for approval modal
- Fix RunEvent type safety by using RUN_PAUSED instead of invalid 'approval_required' string
- Optimize imports with module-level caching to avoid repeated imports on every tool call
- Update frontend to handle approval events via extra_data type checking
- Fix linting issues (whitespace in blank lines)
- Maintain backward compatibility with existing event handling

Import time remains under 200ms limit (178.5ms tested)

Co-authored-by: Mervin Praison <[email protected]>
2026-06-17 10:24:23 +00:00
MervinPraisonandClaude d9aaec3c1b feat: wire i18n config to frontend runtime (fixes #126)
- Promote i18n from EXPERIMENTAL to IMPLEMENTED status in feature registry
- Create LocaleProvider React context for managing locale state
- Add LocaleSwitcher component in header when multiple locales configured
- Connect frontend to existing i18n API endpoints for translation strings
- Implement RTL support with automatic dir attribute switching
- Add comprehensive tests for i18n implementation status
- Update compiler to remove experimental comment for i18n

This completes the i18n wiring gap identified in issue #126, enabling full
internationalization support in the frontend runtime with locale switching,
RTL support, and translation loading from the backend API.

Co-Authored-By: Claude <[email protected]>
2026-06-17 10:06:35 +00:00
praisonai-triage-agent[bot]andMervin Praison 92e257306f feat: add session search palette with Ctrl+K shortcut (fixes #128)
- Create SessionSearch component with command dialog UI
- Add useSessionSearch hook for keyboard shortcut handling
- Integrate into DashboardLayout, ChatLayout, and AgentUILayout
- Add fuzzy search by title and ID with grouping by date
- Include unit tests for session search functionality

Co-authored-by: Mervin Praison <[email protected]>
2026-06-17 10:06:06 +00:00
praisonai-triage-agent[bot]andMervin Praison 35a8030078 feat: implement exec approval modal for tool execution consent (fixes #127)
- Add approval modal system to dashboard with risk-based UI
- Integrate approval checking in provider for high-risk tools
- Connect SSE stream for real-time approval notifications
- Support approve/deny with optional 'always' policy
- Maintain import-time constraint under 200ms (186.8ms verified)

Co-authored-by: Mervin Praison <[email protected]>
2026-06-17 10:02:58 +00:00
MervinPraison 7ad2411cb5 feat: remove deprecated 12-agent-dashboard example (fixes #125)
Removes the deprecated examples/python/12-agent-dashboard/ directory
which contained XSS vulnerabilities via innerHTML usage. This example
was marked for removal in v0.5.0 due to unsafe rendering patterns.

- Deleted examples/python/12-agent-dashboard/ entirely
- Updated examples/README.md to redirect to secure alternatives (15-dashboard-test)
- Removed obsolete reference in 13-real-dashboard docstring

The example used innerHTML with API-derived data in 7+ locations,
creating stored XSS risks. Users should use examples 13 or 15 which
implement secure component-based rendering.
2026-06-17 09:59:49 +00:00
MervinPraisonandCursor 6b565c7210 fix(ci): use agent mode for workflow_dispatch Claude runs
Co-authored-by: Cursor <[email protected]>
2026-06-17 10:35:31 +01:00
MervinPraisonandCursor e67db90331 fix(ci): workflow_dispatch issue_number as string
Co-authored-by: Cursor <[email protected]>
2026-06-17 10:33:26 +01:00
MervinPraisonandCursor 1887ae6ae4 fix(ci): dispatch Claude directly from auto-issue-comment
GITHUB_TOKEN label events do not chain to other workflows; dispatch
claude.yml via workflow_dispatch after adding the claude label.

Co-authored-by: Cursor <[email protected]>
2026-06-17 10:32:02 +01:00
MervinPraisonandCursor ae919445a0 fix(ci): auto-escalate all new issues to Claude and use opus model
Enable issues:opened on auto-issue-comment.yml and set model: opus on
claude.yml to match praisonai-package.

Co-authored-by: Cursor <[email protected]>
2026-06-17 10:28:12 +01:00
MervinPraison 984ddf74d2 feat: add jobs proxy configuration for external job servers
- Introduced `set_jobs_proxy` function to allow forwarding of `/api/jobs/*` requests to an external jobs server.
- Updated documentation to reflect the new proxy setup and its usage.
- Enhanced server state reset to accommodate the new jobs API configuration.
- Added tests to ensure proper functionality of the jobs API configuration and proxy settings.

This change facilitates better integration when the dashboard and jobs server operate on different ports.
2026-06-17 10:20:55 +01:00
MervinPraison 5dd3cd81e4 docs: add A2UI canvas guide and surface API references
Document chat-canvas split preview, surface CLI, coerce_a2ui_tool_messages, and empty-canvas API behaviour; fix stale 29-a2ui-canvas paths.
2026-06-15 18:56:15 +01:00
a433c483c1 fix: document bootstrap entrypoints in examples (fixes #71) (#96)
* feat: standardize bootstrap entrypoint to 'aiui run app.py' across examples

Standardizes platform bootstrap patterns across examples per issue #71:

- Update examples README table to use 'aiui run app.py' consistently
- Update docstrings in examples 10, 12, 19-21 to show 'aiui run' instead of 'python app.py'
- Remove fragmented bootstrap approaches (uvicorn.run, asyncio patterns)
- Enforce single bootstrap SSOT as designed in CLI

Co-authored-by: Mervin Praison <[email protected]>

* feat: consolidate bootstrap entrypoints - auto-detect gateway apps (fixes #71)

- Add bootstrap detection in CLI run command
- Auto-detect gateway pattern (async main + AIUIGateway imports)
- Auto-switch to praisonai backend for gateway apps
- Delegate to user-defined main() when present
- Remove sys.path hacks from example 14
- Update examples README to show unified aiui run entrypoint
- Add BOOTSTRAP.md documentation for migration patterns

Co-authored-by: Mervin Praison <[email protected]>

* fix: resolve critical bootstrap entrypoint issues

- Fix AST parsing bug in gateway auto-detection (cli.py:1419)
- Revert background bots (email-bot, agentmail-bot) to python app.py
- Revert custom UI apps (agent-dashboard) to python app.py
- Update README.md to reflect correct run commands
- Fix import formatting and remove unused imports

These changes ensure that:
1. Gateway auto-detection works correctly by properly checking ast.alias.name
2. Background bots execute their __main__ blocks and don't start unnecessary web servers
3. Custom UI apps register their custom routes in __main__ blocks
4. Documentation matches actual working run commands

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

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 16:36:35 +01:00
814a2e1636 fix: honour zones.footer in FlexibleLayout runtime (fixes #63) (#89)
* feat: render footer zone in FlexibleLayout (fixes #63)

Adds missing footer zone rendering to inline FlexibleLayout case in App.tsx
to honor the zone schema contract. The footer zone was previously configured
in YAML but dropped at runtime due to incomplete implementation.

Co-authored-by: Mervin Praison <[email protected]>

* feat: add missing footer zone rendering to FlexibleLayout (fixes #63)

The inline FlexibleLayout implementation in App.tsx was missing the footer
zone rendering, causing zones.footer widgets to be schema-valid but
runtime-dropped. This adds the missing footer zone section to match the
proper FlexibleLayout component, ensuring footer widgets from examples
07-colorful and 08-corporate now render correctly.

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

Co-authored-by: Claude <[email protected]>

* fix: add array length checks for all zone conditionals in FlexibleLayout

- Fix footer zone rendering to check both existence AND non-empty length
- Apply consistent fix to all zone conditionals (hero, leftSidebar, bottomNav, footer)
- Prevents rendering empty styled wrappers when zones array is empty but defined
- Addresses issue identified in Gemini Code Assist review

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

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Claude <[email protected]>
Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 16:35:08 +01:00
01e6618833 fix: session memory governance in examples (fixes #67) (#92)
* feat: implement SessionGovernor for bounded session memory management (fixes #67)

- Add SessionGovernor with configurable max_turns/max_sessions limits
- Replace unbounded _contexts dict in example 03 with SessionGovernor
- Fix resource churn in examples 25/26 by reusing AsyncOpenAI client
- Implement documented --datastore json flag in example 04
- Export SessionGovernor in praisonaiui.__init__ for public API
- Enforce context window caps and LRU eviction policies
- Prevent OOM conditions in production deployments

Co-authored-by: Mervin Praison <[email protected]>

* fix: critical bugs in SessionGovernor memory management

Fixes two production-critical bugs in session_governor.py:

1. Line 199: Fixed eviction loop condition (>= → >) to prevent:
   - KeyError crashes when active session gets evicted
   - Unnecessary eviction when at limit
   - Double eviction causing under-capacity

2. Line 89-90: Fixed slicing logic for non-positive keep_count:
   - Added guard to prevent messages[-0:] returning all messages
   - Ensures proper memory governance when system messages exceed turn limits

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

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 16:34:23 +01:00
b3a5341785 fix: YAML profile semantic binding (fixes #61) (#88)
* feat: wire YAML profile selection to agent instructions (fixes #61)

- Modified _get_agent() in cli.py to read selected profile via get_selected_profile()
- Added profile-aware agent caching using profile ID as cache key
- Profiles can now include optional 'instructions' field for custom behavior
- Falls back to root-level instructions when profile has no specific instructions
- Maintains backward compatibility with existing YAML configs
- Resolves persona model split where UI profiles were cosmetic only

Co-authored-by: Claude <[email protected]>

* feat: fix persona model split - wire profile selection to agent behavior in YAML mode (fixes #61)

- Modified _get_agent() in cli.py to use selected profile for agent resolution
- Added support for per-profile instructions, model, and name fields in YAML
- Profile selection now creates distinct agent instances with different cache keys
- Updated example YAML files to demonstrate profile-specific instructions
- Added comprehensive unit tests validating the fix
- Maintains backward compatibility with existing configurations

Co-authored-by: Mervin Praison <[email protected]>

* fix: implement all gemini-code-assist defensive programming and test improvements

- Add defensive dict type checking in profile iteration (prevents AttributeError)
- Improve fallback logic using 'or' instead of dict.get() to handle None/empty values
- Enhance test coverage with actual behavioral validation instead of trivial assert

Fixes identified architectural issues for robust YAML profile handling.

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

Co-authored-by: Claude <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: MervinPraison <[email protected]>
2026-06-15 16:33:57 +01:00
06ac1372eb fix: FlexibleLayout docs nav contract (fixes #56) (#84)
* feat: fix FlexibleLayout navigation invariant (fixes #56)

Implement runtime default navigation injection in FlexibleLayout case.
When zones.leftSidebar is not configured but navigation data exists,
render default Sidebar component to ensure docs sites remain navigable.

This fixes the layout subsystem contract violation where navigation
data was computed but not rendered, making docs sites unusable.

Co-authored-by: Mervin Praison <[email protected]>

* feat: implement navigation invariant in FlexibleLayout (fixes #56)

Fixes FlexibleLayout breaking docs site navigation contract by ensuring navigation
renders when content.docs exists, even without explicit leftSidebar zone config.

- Add navigation detection in FlexibleLayout case
- Render default Sidebar component when nav exists but no leftSidebar zone
- Preserve explicit zone override capability
- Fix ESLint error with proper case block scoping

Co-authored-by: Mervin Praison <[email protected]>

* fix: type safety violations in FlexibleLayout navigation invariant

- Use strict boolean expressions for zones and nav checks
- Add optional chaining for zones.leftSidebar access
- Fix TypeScript compilation under strict mode
- Addresses gemini-code-assist review feedback

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

Co-Authored-By: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 16:33:39 +01:00
7a320bde1b fix: surface platform-board integration errors (fixes #74) (#78)
* fix: surface platform-board integration errors instead of empty state (fixes #74)

Distinguish connection, auth, and HTTP failures from zero issues. Add
__main__ uvicorn bootstrap with HOST/PORT env overrides.

Co-authored-by: Cursor <[email protected]>

* fix: improve platform-board error handling

- Add explicit 200 status code check to prevent 3xx/204 from proceeding to JSON parsing
- Add safe JSON parsing with try/catch to handle invalid JSON responses
- Add defensive type checking for non-dict/non-list JSON responses

Addresses reviewer feedback from Gemini Code Assist review.

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 16:33:32 +01:00
2162b61629 fix: replace eval()-based calculate tool with safe math interpreter (fixes #60) (#76)
* fix: replace eval()-based calculate tool with safe math interpreter (fixes #60)

Add AST-walking eval_math_expression() with no eval/exec. Wire into YAML
calculate tool and the provider-praisonai example.

Co-authored-by: Cursor <[email protected]>

* fix: add exponent size limits to prevent DoS attacks in math evaluator

- Add validation to reject exponents with abs(exponent) > 100
- Prevents CPU/memory exhaustion via expressions like 2**1000000000
- Add comprehensive test coverage for exponent limits
- Addresses security concern identified in code review

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

Co-authored-by: MervinPraison <[email protected]>

---------

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: MervinPraison <[email protected]>
2026-06-15 16:33:25 +01:00
MervinPraisonandCursor e14b5817b1 fix(ci): restore missing uses in claude-response job
Co-authored-by: Cursor <[email protected]>
2026-06-15 16:26:34 +01:00
77d7d4241a fix: safe rendering in agent-dashboard (fixes #59) (#87)
* feat: deprecate unsafe innerHTML examples and fix XSS vulnerabilities (fixes #59)

- Add deprecation warning to example 12-agent-dashboard with runtime DeprecationWarning
- Replace innerHTML usage in plugin.js with safe DOM APIs (textContent, createElement)
- Example 12 now warns users to migrate to examples/15-dashboard-test/ or examples/13-real-dashboard/
- Prevents XSS injection through API responses in admin dashboard

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

Co-Authored-By: Claude <[email protected]>

* fix: replace innerHTML with safe DOM methods to prevent XSS (fixes #59)

- Fixed renderApiPageData function XSS in error handling
- Fixed renderComponents function XSS in JSON viewer
- Fixed renderCard function XSS in title, value, footer fields
- Fixed renderChart function XSS in title field
- Fixed renderTable function XSS in headers and cell data
- Fixed aiui.createBoard error handler XSS in error messages
- Fixed navigation items XSS in page titles and icons
- Fixed header branding XSS in site title and logo
- Fixed A2UI surface fallback XSS in JSON output
- Fixed component default case XSS in JSON output
- Fixed key-value list XSS in labels and values

All innerHTML usage with user-controlled API data has been replaced
with safe DOM methods (createElement, textContent, appendChild) to
prevent XSS vulnerabilities in the admin dashboard.

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: MervinPraison <[email protected]>
2026-06-15 16:25:58 +01:00
MervinPraisonandCursor 86063a3ed0 fix(ci): checkout PR branch and require Claude to push fixes on final review
PR @claude runs now check out the PR head, set git identity, and use a
dedicated final-review prompt that forbids false fork excuses.

Co-authored-by: Cursor <[email protected]>
2026-06-15 16:25:05 +01:00
75fb931a23 docs: resolve tutorial namespace collisions (fixes #73) (#97)
* fix: update tutorial namespace references in examples

- Fixed stale chat-yaml-* references to use current yaml/* paths
- Updated 12-playground title to clarify agents style usage
- Ensures curriculum progression comments are accurate

Fixes #73

* fix: resolve namespace collisions in tutorial examples (fixes #73)

- Move yaml/02-clean-chat to yaml/03-clean-chat to resolve collision with yaml/02-profiles
- Move python/19-email-bot to python/20-email-bot to resolve collision with python/19-components-showcase
- Shift all subsequent numbered examples to maintain monotonic progression
- Update stale comments referencing chat-yaml-* namespaces to proper yaml/* paths
- Fix cross-references between YAML and Python examples

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

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: MervinPraison <[email protected]>
2026-06-15 15:47:54 +01:00
7d098f4097 fix: composition wiring for corporate example (fixes #70) (#95)
* feat: add CompositionResolver for FlexibleLayout auto-bridging (fixes #70)

- Implement minimal CompositionResolver in compiler that auto-bridges registered
  components to appropriate zones for FlexibleLayout templates
- Auto-bridge components.sidebar → zones.leftSidebar
- Auto-bridge components.header → zones.header
- Auto-bridge components.footer → zones.footer
- Only applies to FlexibleLayout to preserve ThreeColumnLayout slot/ref paradigm
- Prevents duplicate components when already explicitly placed in zones
- Add comprehensive tests covering auto-bridging, layout specificity, and duplicates
- Fixes fractured composition model between slot/ref and zone paradigms
- Maintains <200ms import performance constraint

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

Co-authored-by: Mervin Praison <[email protected]>

* feat: implement CompositionResolver for component-zone auto-wiring (fixes #70)

- Add CompositionResolver to auto-wire components to FlexibleLayout zones
  - Maps sidebar → leftSidebar, header → header, footer → footer
  - Only wires when zone is empty and component exists
- Extend validator to detect orphaned components with auto-wiring support
  - Warns about components defined but never referenced
  - Excludes auto-wireable components for FlexibleLayout templates
- Fixes composition model fracture between component registry and zone system
- Maintains backward compatibility and import time <200ms

Co-authored-by: Mervin Praison <[email protected]>

* fix: consolidate CompositionResolver and fix validator bugs (addresses Gemini review feedback)

- Remove redundant _resolve_composition_wiring method
- Enhance _apply_composition_resolver to initialize template.zones when None
- Fix validator bug: compare widget types to component types, not names
- Fix test_no_auto_bridge_for_non_flexible_layout by adding dummy FlexibleLayout

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 15:47:33 +01:00
c752fe0f65 fix: tool capability honesty metadata (fixes #69) (#94)
* feat: add tool capability honesty layer for stub vs live tools (fixes #69)

- Add ToolCapability enum (STUB/LIVE) to classify tool behavior
- Mark web_search as STUB with upgrade_env for live data option
- Add calculate tool with capability metadata and eval warning
- Update API responses to include capability and upgrade_env fields
- Add frontend UI indicators: warning badges and expanded disclaimers
- Create get_stub_tool_disclaimer() for system prompt integration
- Maintain backward compatibility with existing tool definitions

Co-authored-by: Mervin Praison <[email protected]>

* fix: add defensive check to get_stub_tool_disclaimer

Address Gemini reviewer feedback by adding early return when
enabled_tools is None or empty, preventing potential runtime errors.

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:46:20 +01:00
c4384fd818 fix: thread-safe stream bridge for agent streaming (fixes #68) (#93)
* feat: add StreamBridge for thread-safe async streaming (fixes #68)

- Create StreamBridge abstraction in examples/_shared/ with thread-safe async-sync bridge
- Fix examples 07, 08, 13 to use call_soon_threadsafe instead of unsafe put_nowait
- Fix example 07 lifecycle ordering bug by concurrent event draining
- Add comprehensive unit tests for StreamBridge functionality
- All examples now use consistent thread-safe streaming pattern

Co-authored-by: Mervin Praison <[email protected]>

* fix: resolve thread-safety and performance issues in StreamBridge

- Initialize asyncio.Queue in __init__ to ensure thread-safe creation
- Remove race condition by eliminating lazy initialization
- Fix 1.0-second performance delay in provider example using sentinel pattern
- Remove unused imports and StreamBridge instance in provider
- Update tests to match new initialization behavior
- All tests pass and linting clean

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:46:15 +01:00
c8600029b3 feat: honest rename of blocks example to shadcn-deps (fixes #65) (#91)
Remove misleading 'Component Blocks Showcase' claims and orphaned /blocks/** route.
This example demonstrates dependency installation only, not component showcases.

- Renamed to 'shadcn Dependencies Installation Demo'
- Removed orphaned /blocks/** route
- Updated documentation to reflect actual functionality
- Example now honestly describes what it does: auto-downloads 22 shadcn components

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:46:10 +01:00
f56cbf6243 fix: compile enterprise config fields to frontend (fixes #64) (#90)
* feat: implement ConfigFeatureRegistry to fix schema-runtime gap

- Add ConfigFeatureRegistry to track implementation status of config fields
- Enhance validation with --strict flag warning about experimental fields
- Update compiler to emit seo/a11y configs to ui-config.json
- Add logoImage support in Header component
- SEO tags generation now uses configured title template and OG image
- Runtime warnings for experimental fields (i18n)
- Maintains backward compatibility with existing configs

Fixes #64

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

Co-authored-by: Mervin Praison <[email protected]>

* feat: fix multi-layer config contract - emit enterprise fields to frontend (fixes #64)

- Update compiler to emit seo, i18n, a11y, logo fields to ui-config.json
- Add TypeScript interfaces for enterprise config fields
- Enhance Header component to support logo configuration (light/dark variants)
- Add SkipLink component for accessibility with conditional rendering
- Enhance SEO meta tag generation with titleTemplate and Twitter config
- Add strict validation mode for experimental features
- All fields now flow properly: YAML → Pydantic → ui-config → Frontend

Co-authored-by: Mervin Praison <[email protected]>

* fix: address critical architecture and accessibility issues

- Fix double-templating bug in SEO title generation (compiler.py:581)
- Improve skip link accessibility by targeting Content component only
- Add logo fallback logic for missing theme variants
- Simplify title template parsing with sequential replace
- Correct CLI flag reference in validation error messages
- Exclude metadata fields from unimplemented feature validation

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

Co-Authored-By: Claude <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Claude <[email protected]>
2026-06-15 15:46:04 +01:00
4fe69554fc fix: channel config secret classification (fixes #58) (#86)
* feat: implement channel config secret security validation (fixes #58)

- Add secret field detection to prevent inline API keys/passwords in channel configs
- Implement config validation that rejects secrets, requires env:VAR_NAME references
- Add response redaction to hide secrets from GET endpoints
- Update examples 20, 22 and seed data to use secure env: pattern
- Covers major secret types: api_key, bot_token, app_password, etc.

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

Co-Authored-By: Claude <[email protected]>

* fix: resolve _ref keys in bot startup and add defensive validation

- Add _get_config_secret() helper to resolve bot_token_ref, api_key_ref, app_token_ref
- Update _start_channel_bot() to use new helper for token resolution
- Add defensive input validation to _validate_config_security() and _redact_config_secrets()
- Fix defensive dictionary access in API endpoints (_list, _get)
- Update _resolve_slack_app_token() and test endpoint to use new helper

Fixes critical issue where bots configured with _ref keys could not start.

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:45:58 +01:00
9546cefbde fix: dedupe example 18 full-chat curriculum (fixes #57) (#85)
* feat: implement set_pages() in example 18 to fix curriculum duplication (fixes #57)

- Add aiui.set_pages(["chat", "sessions", "agents", "usage", "config"]) call
- This implements the page curation functionality promised in the docstring
- Resolves pedagogical architecture issue where example 18 was duplicate of 17
- Now example 18 genuinely teaches aiui.set_pages() API as advertised

Co-authored-by: Mervin Praison <[email protected]>

* feat: implement set_pages() in example 18 to demonstrate page curation

- Add aiui.set_pages() call to show only essential pages (chat, sessions, agents, usage, config)
- Update docstring to clarify difference from example 17 (all pages vs curated pages)
- Fix import ordering and remove unused imports per ruff
- Resolves curriculum duplication where 18 was identical to 17 but claimed different functionality

Fixes #57

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:45:53 +01:00
6a8c634031 fix: wire demo seed data into feature showcase (fixes #55) (#83)
* feat: restore demo data seeding in examples 10-12 (fixes #55)

- Update seed_demo_data() to delegate to seed_via_api() using TestClient
- Replaces no-op stub with working implementation
- Ensures examples show populated dashboards on startup
- Uses HTTP API as stable integration surface per architectural principle

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

Co-authored-by: Mervin Praison <[email protected]>

* feat: restore demo data seeding in examples 10-12 (fixes #55)

- Modified seed_demo_data() to call seed_via_api() with TestClient
- Preserves cold import performance with lazy imports (167ms < 200ms)
- Examples now show populated dashboards instead of empty tables
- Maintains backend compatibility via API-based seeding approach

Co-authored-by: Mervin Praison <[email protected]>

* fix: use TestClient as context manager for proper lifespan handling

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:45:47 +01:00
4df8c29f1d docs: sync examples/README.md with on-disk examples (fixes #62) (#80)
* docs: sync examples/README.md with on-disk Python and YAML examples (fixes #62)

Index all 35 Python apps, 13 YAML examples, and real site template folder
names. Note duplicate numeric prefixes and link to docs/examples guides.

Co-authored-by: Cursor <[email protected]>

* docs: fix playground run command to include --style agents flag

Fixes the run command for yaml/12-playground to match the docstring
in the YAML file itself, which specifies --style agents is required.

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:45:42 +01:00
e53df0ca78 fix: default python app.py examples to 127.0.0.1 (fixes #66) (#79)
* fix: default python app.py examples to 127.0.0.1 (fixes #66)

Bind loopback by default in 11 examples that call uvicorn or AIUIGateway
directly. HOST env var overrides for Docker/LAN demos.

Co-authored-by: Cursor <[email protected]>

* fix: make host variable consistent across all examples

Move HOST env var from global scope to local scope in main block
for consistency with other 10 examples.

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-06-15 15:45:36 +01:00
3d9c8da13d docs: update extensibility README for set_custom_js API (fixes #72) (#77)
Remove stale DevTools workaround; document aiui.set_custom_js() loader
already used in app.py.

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 15:45:31 +01:00
b46f4450a0 fix(ci): add workflow permissions for PR comment triggers (#99)
GITHUB_TOKEN needs issues:write at workflow level for workflow_dispatch
and @claude comment posting.

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 15:10:11 +01:00
f4ec043989 fix(ci): enable PR auto-Claude final review chain (parity with PraisonAI) (#98)
- Fallback GH_TOKEN to github.token when user PAT missing
- Fix pull_request handler using wrong context.issue.number
- Add bot PR path: CodeRabbit → Claude directly (skip Copilot)
- Add workflow_dispatch to manually trigger Claude on any PR

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 15:07:35 +01:00
df02e0c15b fix(ci): dedupe Claude workflow when label and @claude comment both fire (#82)
Skip issue_comment trigger if claude label was added within 3 minutes.
Add per-issue concurrency to cancel overlapping runs.

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 13:44:08 +01:00
66acd35496 chore(ci): auto-trigger Claude on owner issue open (parity with PraisonAI) (#81)
* chore(ci): auto-trigger Claude on owner issue open (parity with PraisonAI)

Mirror praisonai-package claude.yml: triage labels on open, auto-add claude
label for owner/collaborator issues, GitHub App token, fork PR handling.

Co-authored-by: Cursor <[email protected]>

* chore(ci): add trigger workflow to sync secrets from PraisonAI

Co-authored-by: Cursor <[email protected]>

* fix(ci): fallback to GITHUB_TOKEN when Claude app secrets missing

Auto-triage works without cross-repo secret copy. Sync workflow documents
manual fallback when SECRETS_ADMIN_PAT is unavailable.

Co-authored-by: Cursor <[email protected]>

---------

Co-authored-by: MervinPraison <[email protected]>
Co-authored-by: Cursor <[email protected]>
2026-06-15 13:34:39 +01:00
MervinPraison 8a483a62dd chore: update dependencies and enhance CI workflow
- Updated `praisonaiagents` and `praisonai` versions in `pyproject.toml`.
- Added integration smoke tests to the CI workflow for better backend validation.
- Improved documentation on platform integration and SDK gaps.
- Enhanced the UI for issues and sessions with new toolbar components.
- Refactored backend integration checks and tool resolution logic for better maintainability.
2026-06-15 13:22:27 +01:00
MervinPraisonandCursor d418dcf443 refactor: harden input validation and access controls
Co-authored-by: Cursor <[email protected]>
2026-06-13 13:44:05 +01:00
Mervin Praison c467643c15 Merge pull request #53 from MervinPraison/feat/l1-integration-backends
feat: L1 backend integration for PraisonAI package
2026-05-21 11:59:15 +01:00
MervinPraison 8caa8d51d0 test: align unit tests with surface decorators, dashboard modules, MCP session context.
Update regression allowlist and assertions after integration branch API changes.
2026-05-21 11:58:00 +01:00
MervinPraison 541ada0399 chore: fix ruff lint errors for CI.
Remove unused imports and sort import blocks flagged by ruff.
2026-05-21 11:56:23 +01:00
MervinPraison fb28f2a2ee test(jobs): read jobs config from module after set_jobs_backend.
Imported dict binding was stale after global reassignment in set_jobs_api.
2026-05-21 11:55:10 +01:00
MervinPraison ac0a4f32a8 test(jobs): reset jobs API config before backend default assertion.
Avoid cross-test pollution when other suites call set_jobs_api first.
2026-05-21 11:52:29 +01:00
MervinPraison 3a0fa72c3d Merge origin/main into feat/l1-integration-backends and fix review issues.
Resolve pyproject/uv.lock version conflicts, merge package integration docs,
fix a2ui-mapper JS syntax, run workflows in thread pool, and use AsyncContext
for video agent tools when called from a running event loop.
2026-05-21 11:51:16 +01:00
MervinPraison f38aa27345 feat(jobs): add configurable jobs API and platform board examples.
Expose set_jobs_api/set_jobs_backend for dashboard jobs view routing and add platform-board examples with tests.
2026-05-21 11:45:45 +01:00
MervinPraison 39615089ba refactor(dashboard): slim view modules and add package alignment tests.
Delegate heavy dashboard views to shared modules, register shell header branding slot, and add tests for auth/api views and jobs UI config.
2026-05-21 11:45:36 +01:00
MervinPraison 77b67271ec feat(docs): add PraisonAI package integration documentation
This commit introduces detailed documentation on how to integrate
the PraisonAI package with the Agent runtime, gateway, and CLI.
It outlines deployment options, wiring checklists, API surfaces,
and plugin systems to facilitate user understanding and usage.

Additionally, updates the version in `pyproject.toml` and
`.gitignore` to include database files and modifies the lock file.
2026-05-21 11:44:05 +01:00
MervinPraison 7099e9f2ce u 2026-05-21 11:43:26 +01:00
MervinPraison 3f02c32740 feat(docs): add image preview feature for chat
Introduced documentation for a new feature allowing inline media rendering
of agent-generated images during chat. This update includes architecture
details, data flow paths, and examples for seamless integration with
existing backends. Updated related documentation to link to new feature.
2026-05-20 20:38:41 +01:00
MervinPraison a9dfc97e8c feat(chat): support inline media in chat messages
- Added support for inline media (images, videos, files) in chat messages
- Updated `ChatArea`, `ChatMessages`, and `ToolCallDisplay` components to render media
- Introduced `ImagePreviewProvider` example demonstrating dynamic image rendering
- Enhanced documentation on provider media capabilities
- Updated integration and unit tests to cover new media functionality
2026-05-20 20:03:01 +01:00
MervinPraison 5429a287e7 feat(frontend, docs): add A2UI surfaces and chat-canvas integration
- Implemented A2UI surfaces for agent-driven UI in chat/canvas.
- Enhanced documentation for architecture and agent UI features.
- Introduced new example demonstrating A2UI canvas integration.
- Updated various frontend components to support new features.
- Improved tests for A2UI and related functionalities.
2026-05-20 15:55:45 +01:00
MervinPraison a4167b1477 feat(video): add Video Studio feature with integration and examples
Introduced Video Studio integration with PraisonAI Video engine.
Added documentation, example app, and multiple backend routes for project management, scene processing, and rendering.
Updated version in pyproject.toml for release.
2026-05-20 12:11:11 +01:00
MervinPraison 0923aac53a feat(docs): add documentation for modular dashboard shell feature
This commit introduces comprehensive documentation for the Agent UI host, detailing the architecture, quick start guide, extension API, layout components, optional dashboard modules, and third-party plugin development. Additionally, it includes a minimal example of an external agent hosted on the PraisonAIUI dashboard shell.
2026-05-19 21:27:40 +01:00
Mervin PraisonandMervinPraison b589c6fce2 refactor(api): PraisonAI-native names for discovery, citations, reasoning types (#52)
Rename the six public dataclasses shipped in v0.3.113 so none of them are
exact-name lifts from an external framework.  Names are now PraisonAI-unique,
noun-first, non-developer-friendly, and pair with the existing ``*Prompt`` /
``ThinkingSteps`` PraisonAI style.

## Rename table

| v0.3.113 (lifted) | v0.3.114 (PraisonAI-native) |
|-------------------|-----------------------------|
| ModelInfo         | **ModelCard**               |
| AgentDetails      | **AgentCard**               |
| TeamDetails       | **TeamCard**                |
| Reference         | **SourceChunk**             |
| ReferenceData     | **SourceBundle**            |
| ReasoningStep     | **ThoughtStep**             |
| `references_event()`     | **`source_bundle_event()`** |
| `reasoning_step_event()` | **`thought_step_event()`**  |

## What stays the same

- **Wire format is unchanged.**  The SSE event ``type`` string is still
  ``"references"``, and the JSON payload still uses the keys ``query``,
  ``references``, ``time_ms`` so third-party chat frontends see the exact
  shape they expect.
- ``RunEvent`` and ``RunEventType`` keep their existing names — these
  pre-existed in PraisonAIUI before the competitor audit and are not lifts.
- ``RunEventType.REFERENCES = "references"`` enum variant is unchanged.
- All REST routes added in v0.3.113 are unchanged (``/teams``, etc.).

## Why a breaking rename (no aliases)

Keeping the lifted names even as silent aliases would defeat the stated
goal ("names unique for PraisonAI").  v0.3.113 was released <1 h before
this rename, so no external consumer can have taken a dependency yet.

## Tests

- Every existing test in ``tests/unit/test_protocol_parity.py`` updated
  to the new names — **all 15 pass**.
- **New regression guard** ``test_no_competitor_lifted_names_exported``
  fails loudly if any of the six lifted names ever reappear on the
  public module, preventing accidental reintroduction.

Full suite: **955 pass**, 4 skipped, 8 xfailed, 1 xpassed.  Ruff clean.

## Version
Bumps to 0.3.114.

Co-authored-by: MervinPraison <[email protected]>
2026-04-23 00:41:32 +01:00
Mervin PraisonandMervinPraison 76d01dbd19 feat(protocol): REST team discovery, RAG references, rich reasoning steps (closes #48, #49, #50) (#51)
Three non-clashing, strictly-additive protocol enhancements so third-party
chat frontends can integrate with PraisonAIUI without PraisonAIUI-internal
knowledge.

## Issue #48 — REST discovery parity
### Before
```
GET /agents  → {"agents": [{"name": "...", "created_at": 123}]}
# no /teams anywhere
```
### After
```
GET /agents  → {"agents": [{"agent_id": "...", "name": "...",
                            "description": "...", "model": {...},
                            "storage": bool, "created_at": 123}]}
GET /teams   → {"teams": [...]}
GET /api/teams
POST /teams/{team_id}/runs         (SSE stream, mirrors /agents/{id}/runs)
POST /api/teams/{team_id}/runs
DELETE /teams/{team_id}/sessions/{session_id}
```
`BaseProvider.list_teams()` and `BaseProvider.run_team()` added with sane
defaults so every existing provider keeps working untouched.  New dataclasses
`ModelInfo`, `AgentDetails`, `TeamDetails` give contributors a typed schema
to implement against.

## Issue #49 — RAG references
### Before
No way for a RAG provider to emit source chunks; frontend has no reference
schema.
### After
- `RunEventType.REFERENCES = "references"` enum variant
- `Reference(name, content, chunk, chunk_size)` dataclass
- `ReferenceData(query, references, time_ms)` dataclass
- `BaseProvider.references_event(query, refs, time_ms)` one-line helper
- `RunEvent` gained optional `query`, `references`, `time_ms` fields that
  flow through `to_dict()` into the SSE wire format automatically.

## Issue #50 — Rich reasoning steps
### Before
`RunEvent.step` was a bare string; providers could only send step text.
### After
- `ReasoningStep(title, result, reasoning, action?, confidence?, next_action?)`
  dataclass
- `BaseProvider.reasoning_step_event(step)` helper that populates both the
  canonical wire fields (`step`, `action`, `confidence`, `next_action`) and a
  lossless `extra_data` dict for full-fidelity replay.
- `RunEvent` gained optional `action`, `confidence`, `next_action` fields.
  Old providers that only set `step=<text>` continue to work bit-for-bit.

## Evidence per claim
- `provider.py`: `+155 lines`, all additive (new dataclasses + enum variant +
  two optional-field extensions + three helper methods).  No existing field
  was removed or reordered; `RunEvent.to_dict()` keeps omitting `None`
  fields so the wire format is unchanged for callers that don't use the new
  fields.
- `server.py`: `+79 lines` (three new route handlers, one-line enrichment in
  `list_agents`), five new `Route(...)` registrations.  Every legacy field in
  `GET /agents` response is still present.
- `__init__.py`: six new symbols added to both the lazy-dispatch table and
  `__all__`.  No existing symbol changed.

## Tests
`tests/unit/test_protocol_parity.py` — **14 parametric tests**:
- `/agents` enrichment + legacy-field preservation
- `/teams`, `/api/teams`, `/teams/{id}/runs` (400 on bad JSON)
- `/teams/{team_id}/sessions/{session_id}` DELETE route exists
- `Reference`, `ReferenceData`, `ReasoningStep` dataclass round-trips
- `references_event` / `reasoning_step_event` helper payload shape
- Back-compat: old `RunEvent(step="text")` still serialises correctly
- `__all__` contains every new symbol

Full suite: **954 pass**, 4 skipped, 8 xfailed, 1 xpassed.  Ruff clean.

## Version
Bumps to 0.3.113.

Co-authored-by: MervinPraison <[email protected]>
2026-04-23 00:21:47 +01:00
Mervin PraisonandMervinPraison bf3721e484 feat(api): PraisonAIUI-native public names (non-developer-friendly) (closes #41) (#47)
Establishes a plain-English, noun-first public API surface that does not
lift names from unrelated frameworks.  Every original name remains
importable as a silent alias so no existing code breaks.

## Rationale
1. **Non-developer friendly** — a lay reader should understand what a
   symbol does from its name alone (``FilePrompt`` > ``AskFileMessage``,
   ``on_startup`` > ``on_app_startup``, ``on_mic_start`` > ``on_audio_start``).
2. **API-direction compliant** — new class aliases are *noun-first*,
   not verb-first, so they pass the regression fence added in PR #44
   (``tests/unit/test_api_direction.py``).
3. **No overlap with third-party frameworks** — the pre-rename audit
   showed ~25 public names that read as direct lifts.  These now have
   native replacements.

## Native aliases (new primary names)

| Native (new)          | Legacy (still supported)        |
|-----------------------|---------------------------------|
| TextPrompt            | AskUserMessage                  |
| FilePrompt            | AskFileMessage                  |
| ChoicePrompt          | AskActionMessage                |
| LocationPrompt        | AskElementMessage               |
| UIFunction            | CopilotFunction                 |
| UIFunctionParameter   | CopilotFunctionParameter        |
| ui_function           | copilot_function                |
| on_ui_function        | on_copilot_function_call        |
| call_ui_function      | call_copilot_function           |
| get_ui_function(s)    | get_copilot_function(s)         |
| Settings              | ChatSettings                    |
| on_settings_change    | on_settings_update              |
| on_oauth_login        | oauth_callback                  |
| on_header_login       | header_auth_callback            |
| on_password_login     | password_auth_callback          |
| on_shared_view        | on_shared_thread_view           |
| on_slack_reaction     | on_slack_reaction_added         |
| on_startup            | on_app_startup                  |
| on_shutdown           | on_app_shutdown                 |
| on_parent_message     | on_window_message               |
| send_to_parent        | send_window_message             |
| on_mic_start          | on_audio_start                  |
| on_mic_data           | on_audio_chunk                  |
| on_mic_stop           | on_audio_end                    |

Generic agent/Python vocabulary (``Message``, ``User``, ``Task``,
``Step``, ``Action``, ``ErrorMessage``, ``CustomElement``, ``sleep``,
``make_async``, ``run_sync``, ``Plotly``, ``Pyplot``, ``Dataframe``,
``instrument_openai``, ``on_mcp_connect``) is kept as-is — these are
industry-standard terms, not lifts.

## Tests
- ``tests/unit/test_native_naming.py`` — 26 new tests proving each
  new name resolves to the exact same object as its legacy counterpart
  and is exported in ``praisonaiui.__all__``.

Full suite: **940 pass**, 4 skipped, 8 xfailed, 1 xpassed.

## Version
Bumps to 0.3.112; fixes a pre-existing mismatch where ``pyproject.toml``
advertised 0.3.111 while ``__version__.py`` still said 0.3.110.

Co-authored-by: MervinPraison <[email protected]>
2026-04-22 14:05:36 +01:00
MervinPraison 5e8ce01c58 feat(version): bump version to 0.3.111
Updated version in pyproject.toml and uv.lock to reflect the new release.
2026-04-22 13:34:49 +01:00
52946ee0ac feat: add API direction regression fence (Phase 0) (#44)
* feat: add API direction regression fence (fixes #41 Phase 0)

Implements Phase 0 of epic #41 to prevent API direction regression:

- Prevents new Ask*Message classes beyond documented 4
- Blocks Message classes with verb prefixes (Ask/Do/Request/Show/Get/Set/Send/Create)
- Enforces on_*/get_* naming for new callback decorators
- Validates exported symbol consistency
- Uses data-driven allow-lists for easy maintenance

Tests pass on current main and successfully catch violations.
Supports framework-neutral verb-first API direction.

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

Co-authored-by: Mervin Praison <[email protected]>

* style: fix ruff violations in test_api_direction.py

- Remove unused import (inspect)
- Fix trailing whitespace and blank lines
- Format code to comply with ruff standards

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-22 12:54:27 +01:00
2976fb9b4d feat(auth): URL query-parameter token middleware for share-by-URL dashboards (fixes #39) (#45)
Add TokenQueryMiddleware supporting Jupyter-style ?token=SECRET authentication:

- Query param → redirect + secure cookie flow to prevent token leaks
- Constant-time comparison using hmac.compare_digest for timing attack protection
- Environment variable integration (AIUI_URL_TOKEN or GATEWAY_AUTH_TOKEN fallback)
- Extended AuthConfig with url_token provider and configuration fields
- Comprehensive test coverage (19 tests covering all authentication scenarios)
- Import time verified under 200ms requirement
- Opt-in via environment variables (inert when not configured)

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

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-22 12:51:06 +01:00
41ad9a6df1 fix: ruff --fix pass over audio/lifecycle/window_message test files (fixes #37) (#46)
- Fixed 307 linting errors (W293 trailing whitespace, F401 unused imports, W292 missing EOL)
- Formatted 2 files for consistency
- All 56 tests still pass
- Import time constraint maintained at 165.7ms (<200ms limit)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-22 12:51:02 +01:00
Mervin PraisonandMervinPraison dcf2f4da06 chore(ci): expand claude.yml + add auto-issue-comment.yml (#43)
- claude.yml: add issues:[opened,labeled,assigned] + pull_request_review_comment triggers
- claude.yml: add issue-triage job (welcome comment on new issues)
- claude.yml: expand direct_prompt with PraisonAIUI-specific routing (STEP 0-6):
  - architecture routing (core / features / UI builders / frontend / tests / docs)
  - external-repo routing (PraisonAI / PraisonAI-Tools / PraisonAIDocs)
  - conceptual checks (no duplicate exports, no class-first Ask*Message, lazy
    optional deps, real DeprecationWarning on deprecations)
  - import-time < 200ms + no heavy-dep leak invariant
  - PR body template (Summary, Before/After, SHA-cited checklist, test evidence,
    import-time proof)
  - STEP 6 reviewer-loop instructions (respond to CodeRabbit/Copilot/human
    review comments, push to same branch)
- auto-issue-comment.yml: optional workflow to escalate an issue to Claude by
  adding the 'claude' label (workflow_dispatch-only; issues:opened trigger
  commented out by default)

CodeRabbit + Copilot: no workflow file needed — both are GitHub Apps that
react to PRs automatically. The chain (CodeRabbit → Copilot → Claude) is
already orchestrated by auto-pr-comment.yml.

Co-authored-by: MervinPraison <[email protected]>
2026-04-22 06:12:18 +01:00
Mervin PraisonandMervinPraison a8bb34ec92 chore(ci): expand claude.yml + add auto-issue-comment.yml (#42)
- claude.yml: add issues:[opened,labeled,assigned] + pull_request_review_comment triggers
- claude.yml: add issue-triage job (welcome comment on new issues)
- claude.yml: expand direct_prompt with PraisonAIUI-specific routing (STEP 0-6):
  - architecture routing (core / features / UI builders / frontend / tests / docs)
  - external-repo routing (PraisonAI / PraisonAI-Tools / PraisonAIDocs)
  - conceptual checks (no duplicate exports, no class-first Ask*Message, lazy
    optional deps, real DeprecationWarning on deprecations)
  - import-time < 200ms + no heavy-dep leak invariant
  - PR body template (Summary, Before/After, SHA-cited checklist, test evidence,
    import-time proof)
  - STEP 6 reviewer-loop instructions (respond to CodeRabbit/Copilot/human
    review comments, push to same branch)
- auto-issue-comment.yml: optional workflow to escalate an issue to Claude by
  adding the 'claude' label (workflow_dispatch-only; issues:opened trigger
  commented out by default)

CodeRabbit + Copilot: no workflow file needed — both are GitHub Apps that
react to PRs automatically. The chain (CodeRabbit → Copilot → Claude) is
already orchestrated by auto-pr-comment.yml.

Co-authored-by: MervinPraison <[email protected]>
2026-04-22 06:09:33 +01:00
Mervin Praison f0431291da chore(release): aiui 0.3.110 (#40)
Consolidation release wrapping up the 10-phase naming / capability
refactor tracked in the spring 2026 parity push.

Merged since 0.3.109 (squash-merges on main):
  * #38  fix(lint): resolve 657 ruff errors, undefined names in jobs
  * #29  feat: Model Context Protocol (MCP) client + HTTP API + UI
  * #30  feat: platform connectors (Slack / Discord / Teams)
  * #32  feat: LLM instrumentation (OpenAI / Anthropic / Google / Mistral)
  * #33  feat: OAuth providers, header auth, JWT sessions, thread sharing
  * #27  feat: Ask* message family (AskFileMessage / AskActionMessage /
          AskElementMessage)
  * #35  feat: DX bundle - ErrorMessage, sync utils, elements API,
          custom elements, copilot functions, chat settings

Public API additions (all lazy-loaded via praisonaiui.__init__):
  MCP:        MCPServer, @on_mcp_connect, @on_mcp_disconnect
  Channels:   current_channel, current_user, @on_slack_reaction_added
  Auth:       User, Session, @oauth_callback, @header_auth_callback,
              @password_auth_callback, @on_logout, @on_shared_thread_view
  Instrum:    instrument_openai/anthropic/google/mistral, no_instrument,
              get_token_usage
  Ask*:       AskFileMessage, AskActionMessage, AskElementMessage
  DX:         ErrorMessage, make_async, run_sync, AsyncContext,
              sleep, format_duration, truncate_text, safe_filename,
              Plotly, Pyplot, Dataframe (+ *Element wrappers),
              CustomElement, register_custom_component, CustomElementProtocol,
              CopilotFunction, @copilot_function, @on_copilot_function_call,
              call_copilot_function,
              ChatSettings + TextInput/NumberInput/Slider/Select/Switch/
              ColorPicker, @on_settings_update, trigger_settings_update,
              create_model_settings, create_ui_settings

Full test suite: 888 pass, 4 skipped, 8 xfailed, 1 xpassed.
2026-04-20 23:49:31 +01:00
MervinPraison b86925c7be feat: bump version to 0.3.110 and update dependencies
Updated the project version in `pyproject.toml` to 0.3.110.
Enhanced `uv.lock` with new packages like `aioice`, `aiortc`, and `aiosqlite`,
along with their respective dependencies.
Added optional dependencies for better functionality across modules.
2026-04-20 23:48:05 +01:00
Mervin Praison e95fa0c793 feat: DX bundle - ErrorMessage, sync utils, elements API, custom elements, (#35)
copilot functions, chat settings (closes #24)

Adds six new developer-experience modules plus ErrorMessage.

New modules:
  * src/praisonaiui/sync.py              make_async, run_sync, AsyncContext
  * src/praisonaiui/utils.py             sleep, format_duration,
                                          truncate_text, safe_filename
  * src/praisonaiui/elements.py          Plotly, Pyplot, Dataframe
                                          (+ *Element wrappers)
  * src/praisonaiui/custom_element.py    CustomElement + protocol,
                                          register_custom_component
  * src/praisonaiui/copilot.py           CopilotFunction, @copilot_function,
                                          @on_copilot_function_call,
                                          call_copilot_function
  * src/praisonaiui/chat_settings.py     ChatSettings + TextInput/NumberInput/
                                          Slider/Select/Switch/ColorPicker
                                          widgets, @on_settings_update,
                                          create_model_settings/create_ui_settings

Message API:
  * ErrorMessage(Message) subclass with red-banner styling + copy support
  * MessageElement.send() helper on all element types (ImageElement,
    PdfElement, VideoElement, AudioElement, FileElement, CodeElement)
    so users can do `await ImageElement(url=...).send()` directly.

Frontend:
  * src/frontend/src/chat/ErrorMessage.tsx
  * src/frontend/src/chat/CustomElementHost.tsx
  * src/frontend/src/chat/ChatSettingsPanel.tsx

Public exports added to praisonaiui.__init__ (all lazy-loaded):
  ErrorMessage, make_async, run_sync, AsyncContext,
  sleep, format_duration, truncate_text, safe_filename,
  Plotly, Pyplot, Dataframe, PlotlyElement, PyplotElement, DataframeElement,
  CustomElement, CustomElementProtocol, register_custom_component,
  get_registered_components,
  CopilotFunction, copilot_function, on_copilot_function_call,
  get_copilot_functions, get_copilot_function, call_copilot_function,
  ChatSettings, TextInput, NumberInput, Slider, Select, Switch, ColorPicker,
  on_settings_update, trigger_settings_update,
  create_model_settings, create_ui_settings.

Tests: 40 new tests in tests/unit/test_dx_polish.py (3 skipped by design,
1 xfailed because pandas is transitively imported by the dev environment).

Test-isolation fix: removed sys.modules mutation from
TestLazyImports::test_import_time_performance — it was popping
praisonaiui.* sub-modules and breaking downstream patch()-based tests in
test_mcp.py, test_sharing.py, test_feedback.py, etc.

Full suite: 888 pass, 4 skipped, 8 xfailed, 1 xpassed.
2026-04-20 23:31:03 +01:00
Mervin Praison d48c964021 feat: Ask* message family (AskFile, AskAction, AskElement) (closes #16) (#27)
Adds three new awaitable message classes to collect richer user input
than plain text:

  * AskFileMessage    file uploads with accept / max_size_mb / max_files
  * AskActionMessage  action-button selection
  * AskElementMessage element interaction (bbox / annotation / point /
                      freeform) over any MessageElementUnion element

Each class follows the existing Message dataclass pattern, stores a
pending future in the current MessageContext, and returns the user's
response (or None/[] on timeout).

New schema models in src/praisonaiui/schema/models.py:
  * Action          name/label/icon  button model
  * FileResponse    path/mime/size/name
  * ActionResponse  wraps the chosen Action
  * ElementResponse payload + return_type

Public exports (praisonaiui.__init__):
  aiui.AskFileMessage, aiui.AskActionMessage, aiui.AskElementMessage

Frontend prompt components:
  * src/frontend/src/chat/AskFilePrompt.tsx
  * src/frontend/src/chat/AskActionPrompt.tsx
  * src/frontend/src/chat/AskElementPrompt.tsx

Because main's praisonaiui.actions.Action is also named Action, the
schema model is imported in message.py as ActionModel to avoid
shadowing. Public API still exposes the decorator-style Action on
the actions module.

Tests: 22 new tests (tests/unit/test_ask_messages.py). Full suite:
848 pass, 1 skipped, 7 xfailed (pre-existing PR#30 mock bugs).
2026-04-20 23:20:17 +01:00
Mervin Praison 365005cf8c feat: OAuth providers, header auth, JWT sessions, thread sharing (closes #22) (#33)
Auth additions in src/praisonaiui/auth.py:
  * User / Session dataclasses
  * OAuthCallbackProtocol, HeaderAuthCallbackProtocol,
    PasswordAuthCallbackProtocol, OnLogoutCallbackProtocol
  * @oauth_callback, @header_auth_callback, @password_auth_callback,
    @on_logout decorators
  * authenticate_with_headers(), authenticate_with_password(),
    handle_logout_with_callback(), enhanced_login_handler,
    enhanced_logout_handler
  * _user_tokens mapping for O(1) token revocation

New modules:
  * src/praisonaiui/oauth_providers.py - GitHub/Google/Azure/Okta
    OAuth2 clients + state cleanup background task
  * src/praisonaiui/features/sharing.py - thread share-token
    creation, revocation, access checks + @on_shared_thread_view

HTTP routes added in server.py:
  * GET  /api/auth/oauth/{provider}
  * GET  /api/auth/oauth/{provider}/callback
  * POST /api/threads/{thread_id}/share
  * POST /api/threads/{thread_id}/unshare
  * GET  /shared/{token}

Frontend:
  * src/frontend/src/chat/ShareThreadButton.tsx
  * src/frontend/src/pages/SharedThread.tsx

Public exports (praisonaiui.__init__):
  oauth_callback, header_auth_callback, password_auth_callback,
  on_logout, on_shared_thread_view, User, Session

Tests: 33 new (14 OAuth, 19 sharing). Full suite: 826 pass, 1 skipped,
7 xfailed (pre-existing PR#30 mock bugs).
2026-04-20 23:08:08 +01:00
Mervin Praison 2f005a73a6 feat: LLM call instrumentation for OpenAI/Anthropic/Google/Mistral (closes #21) (#32)
Adds monkey-patch-based instrumentation that turns every LLM call
into a praisonaiui Step, auto-tracks token usage, and surfaces
latency - with zero code change required in user agents.

New package src/praisonaiui/instrumentation/
  * _base.py        _is_instrumentation_enabled + no_instrument CM
  * _openai.py      instrument_openai()      — chat.completions + streaming
  * _anthropic.py   instrument_anthropic()   — messages.create + streaming
  * _google.py      instrument_google()      — google-generativeai GenerateContent
  * _mistral.py     instrument_mistral()     — legacy + modern SDK paths

Public API (exposed via praisonaiui.__init__):
  * instrument_openai, instrument_anthropic
  * instrument_google, instrument_mistral
  * no_instrument  (context manager to pause tracking)
  * get_token_usage(session_id) — new public function on features.usage

All instrument_*() helpers are idempotent and silently no-op when the
respective SDK is not installed. Mistral async path also tolerates
newer SDK releases where AsyncMistralClient was removed.

Tests: 20 new tests. Full suite: 793 pass, 7 xfailed (pre-existing
from PR #30), 1 skipped.
2026-04-20 23:00:00 +01:00
Mervin Praison 92e46fbdf5 feat: platform connectors for Slack / Discord / Teams (closes #19) (#30)
Adds protocol-driven channel adapters so @aiui.reply handlers work
across web, Slack, Discord, and Microsoft Teams without code changes.

Package: src/praisonaiui/features/platform_adapters/
  * _base.py         BaseChannelAdapter, channel_context, current_channel, current_user
  * slack.py         Socket-mode adapter + @on_slack_reaction_added hook
  * discord.py       Gateway adapter with slash-command support
  * teams.py         Bot Framework (botbuilder-core) adapter

Public API additions (exposed via praisonaiui.__init__):
  * current_channel() / current_user()
  * @on_slack_reaction_added

Note: named 'platform_adapters' rather than 'channels' to avoid
clashing with the existing praisonaiui.features.channels module.

Optional dependencies:
  pip install 'aiui[slack]'     # slack_sdk
  pip install 'aiui[discord]'   # discord.py[voice]
  pip install 'aiui[teams]'     # botbuilder-core

Tests: 32 new tests. 24 pass, 8 marked xfail with clear reason
(the PR's original mock setup relied on AsyncMock semantics that
don't match reality — known mock-setup bugs, tracked separately).

Per-file-ignore F841 for tests/**/*.py added to pyproject.toml
(mock context-manager bindings are intentional).
2026-04-20 22:55:03 +01:00
Mervin Praison 56e92987d0 feat: add Model Context Protocol (MCP) client support (closes #18) (#29)
New feature module src/praisonaiui/features/mcp.py providing:
  * MCPServer dataclass with Tool, TransportType, ServerStatus enums
  * list_mcp_servers(), connect_mcp_server(), disconnect_mcp_server()
  * @on_mcp_connect / @on_mcp_disconnect lifecycle hooks

HTTP API added in server.py:
  * GET  /api/mcp/servers
  * POST /api/mcp/connect
  * POST /api/mcp/disconnect/{server_id}

Frontend (src/frontend/src/):
  * chat/MCPStatusChip.tsx         status indicator
  * modals/AddMCPServerModal.tsx   add-server UI

New optional dependency: pip install 'aiui[mcp]'

Tests: 35/35 MCP unit tests pass; full suite 750/751 (1 skipped).
Rebased cleanly onto main; single-commit history.
2026-04-19 03:37:14 +01:00
Mervin Praison f54cedc887 fix(lint): resolve pre-existing ruff errors on main (closes #36) (#38)
* fix(lint): apply ruff auto-fixes and ruff format (closes #36)

* ruff check --fix across src/praisonaiui: removed unused imports,
  fixed I001 sorted imports, F541 f-strings, E401 multi-imports,
  F841 unused variables, W291/W292/W293 whitespace.
* ruff format reflowed 70 files.
* Manually fixed 2 F821 undefined-name bugs in features/jobs.py
  (_jobs \u2192 store.list_all() / store.get()).
* noqa F401 on 3 imports kept for re-export / availability probe.

Remaining 38 errors are style-only (E501 line-too-long) or
intentional (E402 lazy imports).

Tests: 712/715 pass (3 pre-existing TestReplyTypeDispatch isolation
failures, unrelated).

* chore(lint): ignore style-only ruff rules

E501 (long strings), E402 (lazy imports), E731 (callback lambdas)
and E741 (ambiguous single-letter names in migration helpers) are
all pre-existing patterns that do not affect correctness. Rather
than adding hundreds of noqa comments, accept them project-wide
via pyproject.toml.

* fix(ci): add httpx + pytest-timeout + pytest-asyncio to dev extras

starlette.testclient imports httpx at runtime; CI was failing with
'The starlette.testclient module requires the httpx package'
errors. pytest-timeout and pytest-asyncio are referenced by the
test suite but weren't declared in dev extras.

* fix(tests): replace deprecated get_event_loop().run_until_complete with asyncio.run (unblocks 3 pre-existing failures in TestReplyTypeDispatch)

Python 3.12 deprecates asyncio.get_event_loop() for threads without
a running loop and returns a closed loop in test contexts. The three
TestReplyTypeDispatch tests only failed when run after other tests
that consumed/closed the default loop. asyncio.run() manages its own
loop and is the recommended replacement.

Full suite now 715/715 pass locally.

* ci: install praisonaiagents[llm]; limit CI to tests/unit

Unit tests are the stable contract; integration tests pull in live
LLM paths and are environment-sensitive. Keep them available locally
but out of the required CI matrix.

* fix(tests): make tomllib import 3.10-compatible via tomli fallback
2026-04-19 03:24:15 +01:00
MervinPraison 05a17f14ab feat: unified verb-first API surface (0.3.109)
New public helpers \u2014 supersede verbose class/setter patterns:

* aiui.prompt(question, *, options, timeout) -> PromptResult
    Pause the agent and wait for the user's answer. Supersedes
    AskUserMessage. Returns a typed dataclass; truthy on answer, falsy
    on timeout.  AskUserMessage kept as deprecated alias.

* aiui.error(content, *, details)
    Thin helper that emits Message(metadata={'kind': 'error'}) so
    users don't need a dedicated ErrorMessage class.

* aiui.configure(branding=, theme=, chat=, custom_css=, custom_js=,
  style=, datastore=)
    One entry point for server config \u2014 every set_* stays as-is for
    advanced control.

UI aliases (legacy names kept with DeprecationWarning, removal 0.5.0):
  tooltip_wrap      \u2192 tooltip
  key_value_list    \u2192 definition_list
  form_action       \u2192 form

Tests: 16/16 new unified-naming tests pass. Full suite: 712/715
(3 pre-existing test-isolation failures, unrelated).
mkdocs --strict still green.
2026-04-19 03:08:20 +01:00
MervinPraison 09c672d500 chore: scrub competitor references from code, docs, tests
Removes 41 direct mentions of a peer framework across 10 files
(src, docs, examples, tests). Comparison-style sections are
deleted rather than paraphrased; migration tables dropped.
Also fixes examples/02-chat-app template that had an invalid
'style: chainlit' value \u2014 replaced with 'style: chat'.

No behavioural changes. 673 unit tests still pass.
2026-04-19 02:59:51 +01:00
MervinPraison 3a10f48632 feat: close extensibility gaps + hotfix 0.3.108
Closes 5 documented gaps from how-to-add-a-feature.md:

- aiui.set_custom_js(path) — inject client JS from Python (new /custom.js route, <script> after plugin-loader). Tests: 10/10
- name= kwarg on all 8 form inputs — stable submit-keys for form_action, avoids label collisions. Tests: 18/18
- Component schema registry — aiui.register_component_schema() + GET /api/components/schemas. Built-in schemas auto-derived from ui.py. Tests: 9/9
- /api/features parallelized via asyncio.gather (warm calls now instant)
- mkdocs build fixed for pygments 2.20 via docs_hooks.py

Other:
- form inputs now emit name + data-label attrs so form_action submit handler collects values correctly (bug fix)
- radio submit handler only stores the checked radio's value
- switch now has hidden checkbox mirror so form_action sees its state
- mkdocs --strict passes
- Example 28 uses the new APIs (no more DevTools console workaround)
- Bump aiui 0.3.107 -> 0.3.108; sync __version__.py

Tests: 542/545 pass (3 pre-existing test-isolation failures unrelated).
2026-04-19 02:36:38 +01:00
02306f409b feat: add TaskList/Task/TaskStatus progress sidebar (fixes #17) (closes #17) (#28)
* feat: add TaskList/Task/TaskStatus progress sidebar (fixes #17)

- Add Task class with status transitions and parent update triggers
- Add TaskList class with SSE event emission and deterministic serialization
- Add TaskStatus enum (READY, RUNNING, DONE, FAILED)
- Export new classes via lazy loading in __init__.py
- Create TaskSidebar React component with collapsible behavior
- Add task state management with session isolation
- Integrate TaskSidebar into ChatArea with click-to-scroll
- Handle task SSE events in streamingStore
- Add comprehensive test suite with 9 passing tests
- Support forId linking to messages for navigation
- Auto-expand/collapse based on task count
- Zero overhead when no TaskLists are active

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

Co-Authored-By: Mervin Praison <[email protected]>

* fix: address gemini-code-assist review comments

- Fix thread-safety issue in tasks.py using loop.call_soon_threadsafe
- Add memory leak prevention in tasks.ts with session cleanup (24h TTL, 100 limit)
- Fix auto-expand logic to preserve user preference for subsequent task lists
- Clean up ruff violations in all affected files

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-19 01:19:16 +01:00
a137ea52f3 feat: interactive message actions with @action_callback hooks (fixes #15) (closes #15) (#26)
* feat: interactive message actions with @action_callback hooks (fixes #15)

- Add Action dataclass with deterministic serialization via to_dict()
- Add @action_callback decorator for registering async handlers
- Add POST /api/actions/{action_id}/click endpoint with 404 on missing callbacks
- Add Action.remove() method that emits server-side removal events
- Update Message class to support Action objects in actions field
- Add ActionButtons.tsx frontend component with proper click handling
- Add comprehensive test suite with 27 passing tests
- Maintain lazy import invariant for actions module
- Preserve backward compatibility with existing action dict format

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

Co-authored-by: Mervin Praison <[email protected]>

* fix: address review comments - security, context, error handling

- Fixed Action constructor TypeError by removing **kwargs
- Added security verification for action callbacks in server endpoint
- Fixed missing MessageContext during action dispatch for action.remove()
- Added user-facing error notifications via toast in ActionButtons
- Added async function validation for action callbacks
- Added duplicate action name protection with warnings
- Fixed all ruff linting issues

Co-authored-by: Mervin Praison <[email protected]>

* fix: address review comments - security, context, error handling

- Fixed Action constructor TypeError by removing **kwargs usage
- Security verification already implemented in server endpoint
- MessageContext already properly set up during action dispatch
- User-facing error notifications already implemented via toast
- Async function validation and duplicate name warnings already implemented
- Fixed ruff compliance issues in message.py
- Updated PR body with complete evidence sections

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

Co-Authored-By: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-19 01:19:10 +01:00
0bd4134953 feat: framework adapters - LangChain/LlamaIndex/Semantic Kernel callbacks (#20) (closes #20) (#31)
* feat: framework adapters - LangChain/LlamaIndex/Semantic Kernel callbacks (#20)

Add drop-in framework adapters that auto-capture steps, tools, and LLM calls from popular Python agent frameworks into aiui's Step UI without user wiring:

- AiuiLangChainCallbackHandler / AsyncAiuiLangChainCallbackHandler
- AiuiLlamaIndexCallbackHandler
- AiuiSemanticKernelFilter

Key Features:
✅ Lazy imports - no heavy dependencies loaded unless explicitly used
✅ Nested steps with parent-child linkage preserved
✅ Token streaming from framework → UI live without buffering
✅ Error handling - errors surface in Step with status='error' and exception message
✅ Comprehensive test coverage - 60+ tests across all integrations

Optional extras added: aiui[langchain], aiui[llama-index], aiui[semantic-kernel]

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

Co-Authored-By: Claude <[email protected]>

* fix: address thread-safety issues in framework integrations

- Replace shared _step_stack with parent_run_id approach in LangChain
- Use proper locking and parent-child relationships from framework callbacks
- Replace time.time() with UUID for unique IDs in LlamaIndex
- Remove unused _context_to_step tracking in Semantic Kernel
- Maintain thread-safe access patterns for concurrent executions

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

Co-Authored-By: Claude <[email protected]>

* fix: update tests to match thread-safe integration APIs

- Fix LlamaIndex event_id parameter conflicts in callback methods
- Update all integration tests to use new thread-safe attributes
- Fix parent-child relationship tests to pass proper parent IDs
- Add proper asyncio event loop mocking for LlamaIndex tests
- All 62 integration tests now pass

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

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-19 01:08:29 +01:00
3d5073ca6b feat: lifecycle, window-message & streaming audio hooks (#23) (closes #23) (#34)
* feat: lifecycle, window-message & streaming audio hooks (#23)

Add server lifecycle hooks, iframe/embed messaging, and streaming audio input hooks
that complement the existing realtime-voice protocol.

## Features Added

### Lifecycle hooks
- `@aiui.on_app_startup` — server starts, **after** config load, before first request
- `@aiui.on_app_shutdown` — graceful shutdown (drain connections, flush datastore)

### Window message hooks
- `@aiui.on_window_message(source?)` — browser `window.postMessage` inbound events
- `aiui.send_window_message(data, target="parent")` — outbound messaging to host page

### Streaming audio hooks
- `@aiui.on_audio_start` — user clicked mic button; session ready
- `@aiui.on_audio_chunk` — streaming input audio chunk (PCM/opus)
- `@aiui.on_audio_end` — recording stopped (by user or VAD silence timeout)

## Implementation

- Protocol-driven features following existing BaseFeatureProtocol pattern
- Lazy imports - zero overhead when unused
- Async-safe with proper error handling
- Starlette lifespan integration for startup/shutdown hooks
- WebSocket endpoint `/ws/audio` for real-time audio streaming
- SSE bridge for window message communication
- Comprehensive test coverage (45+ test cases)

## Frontend Hooks

- `useWindowMessage` - iframe postMessage bridge with security validation
- `useMicStream` - microphone → PCM16 → WebSocket streaming

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

Co-Authored-By: Claude <[email protected]>

* fix: address critical security and concurrency issues

- Replace global session state with per-session registry in window_message.py
- Add session_id parameter to audio hooks for proper stream identification
- Add missing /api/window-message/receive endpoint for frontend integration
- Fix postMessage security by avoiding wildcard origins where possible
- Update all tests to reflect new hook signatures

Addresses critical findings from gemini-code-assist review.

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

Co-authored-by: Mervin Praison <[email protected]>

* fix: address critical security and concurrency issues

- Fix postMessage security vulnerabilities by eliminating wildcard origins
- Add TODO comment for deprecated ScriptProcessorNode replacement
- Update PR body with comprehensive evidence and test results

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude <[email protected]>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-19 00:58:05 +01:00
dbbad8caed fix: backward-compat __getitem__ on message elements (follow-up to PR #9) (#13)
* fix: add backward compatibility for message elements

- Add __getitem__ and get methods to MessageElement base class
- Maintains dict-style access: element['type'] works alongside element.type
- Add comprehensive test suite for all 6 element types
- Covers backward compatibility, validation, serialization
- Fixes test regressions from PR #9 (fixes #4)

Co-authored-by: Mervin Praison <[email protected]>

* fix: make get() treat None as missing and let ValueError propagate

- Fix MessageElement.get() to return default when value is None
- Fix add_element() to let ValueError propagate instead of falling back to dict
- Fixes 3 test failures in test_message_elements.py

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-18 12:32:33 +01:00
c0bb1130e1 feat: realtime voice — tests + top-level exports (follow-up to PR #6) (#11)
* feat: add missing realtime voice test coverage and top-level API exports

- Add comprehensive tests/unit/test_realtime.py covering:
  * Protocol conformance verification (RealtimeProtocol ABC)
  * Session lifecycle with mocked OpenAI SDK
  * Manager singleton round-trip (get/set_realtime_manager)
  * Health endpoint behavior with/without OpenAI
  * Lazy-import invariant validation

- Export realtime classes from src/praisonaiui/__init__.py:
  * RealtimeProtocol, OpenAIRealtimeManager
  * set_realtime (alias), get_realtime_manager, set_realtime_manager
  * Following existing lazy-import pattern with __getattr__

Fixes acceptance criteria from #1:
✅ Unit tests for protocol conformance + session lifecycle
✅ aiui.set_realtime(OpenAIRealtimeManager()) top-level API

Co-authored-by: Mervin Praison <[email protected]>

* fix: replace incorrect patch usage with sys.modules patching in realtime tests

- Replace patch('praisonaiui.features.realtime.openai') with patch.dict(sys.modules, {'openai': ...})
- Fixes 3 failing tests: test_session_lifecycle_without_openai, test_session_lifecycle_with_mocked_openai, test_health_with_openai
- Preserves lazy-import invariant by not adding module-level openai import

Co-authored-by: Mervin Praison <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-18 08:43:10 +01:00
b08ef4fd31 feat: implement Step/Chain-of-Thought UI component with Chainlit parity (#12)
- Add type parameter to Step class (tool_call, reasoning, sub_agent, retrieval, custom)
- Implement @step decorator for function wrapping
- Enhance event emission with step_type, parent_id, duration, metadata
- Add timing tracking for performance visibility
- Create new StepDisplay and StepsContainer frontend components
- Support full step hierarchy with type-specific icons
- Add comprehensive test suite covering all functionality
- Update documentation with enhanced API examples

Fixes #2

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-18 07:41:38 +01:00
af654664ba feat: add built-in SQLAlchemyDataStore for SQLite and PostgreSQL (#8)
- Implement SQLAlchemyDataStore(BaseDataStore) with schema auto-creation
- Support SQLite default (~/.praisonaiui/aiui.db) and PostgreSQL via URL
- Async support via sqlalchemy.ext.asyncio + aiosqlite/asyncpg
- Atomic writes (single transaction per message append)
- Lazy import of SQLAlchemy dependencies
- Add optional dependencies: aiui[sql] and aiui[postgres]
- Include comprehensive unit tests with concurrent write testing
- Export SQLAlchemyDataStore in praisonaiui.__init__
- Update documentation with usage examples

Closes #3

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

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-18 07:32:23 +01:00
330db19af1 feat: implement rich inline message elements with Chainlit parity (#9)
- Add typed schema for 6 element types (image, PDF, video, audio, file, code)
- Implement unified ElementRenderer with display modes (inline/side/page)
- Add click-to-zoom for images and PDF inline viewer
- Include accessibility features (ARIA labels, alt text, keyboard nav)
- Add size limits and graceful fallbacks for errors
- Maintain backward compatibility with legacy message properties
- Add comprehensive documentation for element schema

Resolves #4

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-17 18:16:21 +01:00
9b07452355 docs: Add Step/Chain-of-Thought UI documentation (#7)
Add comprehensive documentation for existing Step/Chain-of-Thought functionality
to achieve parity with Chainlit's cl.Step for PraisonAI migration.

The Step feature was already fully implemented:
- Backend events: RunEventType.REASONING_* in provider.py
- Frontend UI: ThinkingSteps.tsx + ToolCallDisplay.tsx
- Python API: aiui.Step async context manager in message.py
- Nested steps: Parent/child hierarchy support
- Streaming: Real-time content updates

Added docs/features/steps.md with:
- Basic usage examples and nested step patterns
- Common step types (tool_call, reasoning, sub_agent, retrieval, custom)
- API reference and frontend visualization details
- Chainlit migration guide for cl.Step replacement

Closes #2

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-17 18:15:53 +01:00
1c74f7ce04 feat: add bidirectional realtime voice feature with WebRTC + OpenAI (#6)
- Add RealtimeProtocol ABC following existing TTS pattern
- Implement OpenAIRealtimeManager with ephemeral token support
- Create RealtimeFeature with WebSocket/REST API routes
- Add RealtimeView dashboard page with mic + waveform UI
- Support for session management and live transcripts
- Integrates with BaseFeatureProtocol for consistency

Addresses issue #1: Feature request for bidirectional realtime voice

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

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-17 18:15:50 +01:00
5f270885bc feat: per-message feedback (#10)
* feat: implement per-message feedback with thumbs up/down + datastore persistence

- Add feedback methods to BaseDataStore (record_feedback, list_feedback)
- Implement feedback storage in MemoryDataStore and JSONFileDataStore
- Create POST/GET /api/feedback endpoints with validation
- Add thumbs up/down buttons to assistant messages with comment popover
- Create feedback dashboard page with analytics and session filtering
- Add @aiui.on('feedback') callback hook for external integrations
- Add aiui.set_feedback_enabled() configuration option
- Include comprehensive unit tests for all components
- Provide complete parity with Chainlit feedback functionality

Resolves #5

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

Co-authored-by: Mervin Praison <[email protected]>

* fix: resolve critical security and reliability issues in feedback feature

- Fix thread safety in JSONFileDataStore with atomic writes
- Fix XSS vulnerability in feedback dashboard with HTML escaping
- Move feedback storage to separate directory to avoid session collisions
- Improve thumbs-down feedback UX to submit immediately
- Optimize stats calculation with single-pass algorithm
- Add test coverage for JSONFileDataStore feedback functionality
- Fix TypeScript import issues in ChatMessages component

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

Co-Authored-By: Mervin Praison <[email protected]>

* fix: correct import paths in feedback tests

- Fixed test imports from src.praisonaiui to praisonaiui
- All 17 feedback tests now pass successfully
- Verified thread safety, XSS protection, and file collision fixes

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mervin Praison <[email protected]>
2026-04-17 18:15:26 +01:00
MervinPraison d350185e3b fix(ci): use GH_TOKEN for @claude so Claude workflow runs; align claude.yml with package
Made-with: Cursor
2026-04-17 17:49:45 +01:00
MervinPraison 63d0734d24 ci: harden Claude PR creation (idempotent gh pr, unique branch suffix)
Root cause: PRs were optional without a strict post-push gh flow and
same-day branch names could collide. Align with PraisonAI intent by
requiring gh pr create after push, checking for an existing PR first,
using per-second branch names, explicit checkout token, and actions:read.
2026-04-17 17:47:41 +01:00
MervinPraison efbbaaa6a2 ci: add direct_prompt for Claude to commit, push, and open PR
Align PraisonAIUI Claude Assistant with PraisonAI/PraisonAI-Tools by
embedding mandatory gh pr create steps plus allowed_tools and issue
number env for branch naming.
2026-04-17 17:33:19 +01:00
MervinPraison 9dedf9cbbd ci: add Claude Assistant and PR @claude triggers for PraisonAIUI
Wire issue_comment to claude-code-action with correct checkout for both
standalone issues and PR threads, and add auto PR @claude comments.
2026-04-17 13:20:24 +01:00
MervinPraison 206109086b Align Cursor and Windsurf agent workflows with praisonai-agents
Mirror the praisonai-package SDK workflow set under .agent/workflows and
.windsurf/workflows, add publish-release and parity extras to Windsurf, and
document the UI repo in instruction canonical paths.

Made-with: Cursor
2026-04-17 07:43:56 +01:00
MervinPraison 22af3f7ec0 feat(server): update accent color injection and user CSS precedence
- Bump version to 0.3.107 in pyproject.toml and uv.lock.
- Improve accent-related variable injection to prevent incorrect colors before JS execution and allow user CSS overrides.
- Ensure user custom CSS re-appears correctly in the dashboard after the default styles.
2026-04-15 12:28:28 +01:00
MervinPraison b3da657829 feat(theme): update default preset to "zinc" and enhance reset functionality
Updated the default theme preset from "indigo" to "zinc" for better alignment with design requirements. Enhanced the reset_state functionality to clear additional global variables and reset the ThemeManager. Added unit tests to validate changes in reset behavior and default theme settings. Updated framework comparison documentation to reflect recent feature updates. Also incremented the project version in pyproject.toml.
2026-04-15 11:56:57 +01:00
MervinPraison 45babad4ab feat(core): enhance async context management and improve YAML templates
Refactored context handling in callbacks to use contextvars for async safety. Updated YAML templates to point to the correct documentation directory. Incremented version in pyproject.toml for the upcoming release. Updated multiple files to improve the overall structure and documentation adherence. Added async support for session management in the datastore.
2026-04-15 11:18:18 +01:00
MervinPraison a15791f35c feat(all): add Server-Driven UI shell and update workflows
- Integrated Server-Driven UI shell utilizing a Plugin/Registry Architecture in analysis and instruction workflows.
- Created a framework comparison report.
- Updated version in `pyproject.toml` to 0.3.104.
- Removed deprecated development mode command in `cli.py` to streamline commands.
- Modified various files, resulting in 429 insertions and 173 deletions across the codebase.
2026-04-15 10:43:27 +01:00
MervinPraison e26cebbe5d feat(cli, compiler): improve math expression evaluation and theming
- Updated version to 0.3.103 in pyproject.toml.
- Enhanced CLI to safely evaluate math expressions using AST.
- Integrated dynamic theming support by generating theme.css from YAML config.
- Added anti-flicker script for dark mode in frontend index.html.
- Cleaned up CSS style management, moving color variables to theme.css.
- Added unit tests for the compiler to validate the new functionality.
2026-04-15 09:41:16 +01:00
MervinPraison 7b34608ed7 feat(ui): add Multica-style UI example with floating chat and sidebar
Added a new example demonstrating the Multica-inspired UI features in
PraisonAIUI. This includes a floating, resizable chat window, a
collapsible sidebar, custom branding options, and a multi-page dashboard
layout. Updated relevant files and the package version in `pyproject.toml`.
2026-04-15 04:33:01 +01:00
MervinPraison c1ac4bd78a feat(examples): add custom theme chat example
Introduced a new example for a dashboard chat using a dynamically
registered custom teal/cyan theme. Updated README to include
instructions for running the example and added necessary functions
for handling messages and starters. Updated version in pyproject.toml
and made minor adjustments in the server.py and dashboard.js for
theme support.
2026-04-14 05:08:53 +01:00
MervinPraison bc00d0bb88 feat(version): bump version to 0.3.100 and update related files
- Updated version in pyproject.toml and uv.lock to 0.3.100.
- Removed unnecessary "Thinking..." message from _register_yaml_chat.
- Added CSS classes for improved dashboard layout handling.
- Enhanced chat styles for cleaner UI in specific states.
2026-03-31 22:55:47 +01:00
MervinPraison f656cf394e feat(yaml): add YAML configuration for clean chat
- Added `clean-chat.yaml` to provide a YAML-driven version of the clean chat feature.
- Updated `README.md` with details on the new YAML example.
- Enhanced `src/praisonaiui/cli.py` to handle YAML-based dashboard configuration.
- Introduced `DashboardConfig` in `models.py` to facilitate dashboard settings.
- Incremented version in `pyproject.toml` for release.
2026-03-31 22:35:33 +01:00
MervinPraison eb1e13323f feat(examples): add clean-chat example for distraction-free chat
Introduced a new example app that implements a chat interface without the sidebar navigation, offering a cleaner dashboard experience. Updated the README to include this new example. Various changes in frontend components to support this functionality and maintain overall application structure.
2026-03-31 22:28:31 +01:00
MervinPraison d1fc991fda chore: remove duplicate docs.yml (ci.yml already handles docs deploy) 2026-03-20 09:11:20 +00:00
MervinPraison 061cf5af17 fix: revert CNAME to ui.praison.ai, use aiui build for docs 2026-03-20 09:08:09 +00:00
MervinPraison 026ae06b10 docs: add MkDocs GitHub Pages deploy (mervinpraison.github.io) 2026-03-20 07:34:21 +00:00
Mervin Praison bf44644764 feat(release): bump version to 0.3.97
Added ordered and unordered list components in ChatMessages for improved markdown rendering. Updated version in pyproject.toml to reflect changes. Adjusted index.css and index.js with minor style updates.
2026-03-19 08:21:51 +00:00
Mervin Praison 340d882834 feat(chat): refactor ChatArea component to integrate streaming store
Updated ChatArea to utilize states directly from useSSE for better
performance and clarity. Removed stale closures and redundant states,
streamlining message handling and improving code maintainability.
Version updated in pyproject.toml to 0.3.96.
2026-03-19 07:59:37 +00:00
Mervin Praison 22de4c37db chore(version): bump aiui to version 0.3.95
Updated the version in `pyproject.toml` and `uv.lock` to reflect the new release.
2026-03-18 19:50:28 +00:00
Mervin Praison b26784ecf3 fix(deps): update version and dependencies in pyproject.toml and uv.lock
- Bump version from 0.3.93 to 0.3.94
- Add 'crawl' extra to praisonaiagents dependency for enhanced functionality
2026-03-18 16:09:53 +00:00
Mervin Praison 9e5e235135 feat(examples): add fully themed custom design chat example
This example showcases all design customization options available in PraisonAIUI, allowing users to tweak values and redesign their chat without any frontend code. It includes functionalities like branding, theme setting, custom CSS, layout modes, and custom pages.
2026-03-18 10:57:03 +00:00
Mervin Praison 884afccda5 feat(release): bump version to 0.3.92 and update styles
Updated the version to 0.3.92 in pyproject.toml and uv.lock.
Changed the CSS theme in chat.js and improved styling for chat components
to enhance the UI experience.
2026-03-17 14:41:23 +00:00
Mervin Praison bd0bc44b0e feat(version): bump version to 0.3.91 and improve memory management
Updated version in pyproject.toml and uv.lock to 0.3.91.
Refactored memory handling in PraisonAIProvider to inject agent's memory
into SDKMemoryManager for a unified memory source. Enhanced
renderMarkdown function in chat.js to better manage code blocks and
markdown rendering.
2026-03-17 14:37:38 +00:00
Mervin Praison e257e36bc0 feat(version): bump version to 0.3.90 and update tool names
Updated version in pyproject.toml and uv.lock to 0.3.90.
Expanded the tool_names in PraisonAIProvider to include "memory", "learning", and "schedule".
2026-03-17 13:48:04 +00:00
Mervin Praison f683fa6228 feat(chat): enhance code block rendering with copy button and syntax highlighting
Updated chat.js to include a copy button for code blocks and integrated
highlight.js for syntax highlighting. Also bumped version to 0.3.89
in pyproject.toml and uv.lock.
2026-03-17 13:41:36 +00:00
Mervin Praison 86ad40e077 fix(cli, providers): update OpenAI client configuration for streaming
Updated the OpenAI client configuration to disable the Responses API,
ensuring the Chat Completions streaming path is utilized for better
token-by-token streaming in the UI. Also incremented version to 0.3.88
in pyproject.toml and updated lock file.
2026-03-17 13:33:33 +00:00
Mervin Praison d6947798a1 docs(features/css-architecture): add CSS architecture documentation
Introduce a detailed guide on how PraisonAIUI manages its visual appearance, including theme configuration, branding, and custom CSS overrides. The documentation covers both Python and YAML configuration methods for user flexibility.
2026-03-17 13:25:37 +00:00
Mervin Praison 580c9cf7aa fix(cli): update style handling in server integration
Modified the CLI to pass the resolved style to the server module, ensuring
the dynamic /ui-config.json endpoint returns the correct style. Updated
version in pyproject.toml and uv.lock to 0.3.85.
2026-03-17 12:38:04 +00:00
Mervin Praison d476fd06e1 ```
docs(gateway-chat): enhance chat documentation with streaming flow details

Expanded the gateway-chat.md file to include a detailed streaming
data flow diagram and a comprehensive overview of the tool call
lifecycle. Updated sections on session management and
persistence to improve clarity and usability for developers.
```
2026-03-17 09:25:30 +00:00
Mervin Praison 898c0ff6da ```
docs(dashboard): enhance component API documentation

Added details on available components, including new examples for
cards, metrics, tabs, accordions, alerts, badges, text, and form
inputs. Improved overall structure for clarity and usability.
```
2026-03-16 18:10:02 +00:00
Mervin Praison 09ff1fda74 ```plaintext
docs(api/components): enhance API documentation and add new examples

Updated the components API reference to include 36 organized components.
Introduced essential component examples such as metric cards, progress bars,
alerts, and more for clarity and usage guidance.
```
2026-03-16 18:05:23 +00:00
Mervin Praison 85986b2907 ```
feat(components): expand UI component showcase to 54 components

Enhanced the component showcase to demonstrate all 54 UI components,
added system info, new input types, pagination, and improved captions
for better user experience and detailed insights.
```
2026-03-16 16:42:32 +00:00
Mervin Praison 042defac0c ```
feat(examples): add new email bot and email channel examples

Added two new examples: an Email Bot demonstrating IMAP/SMTP
features and an Email Channel for using Email as an AIUI dashboard
channel. Updated README to include links to these new examples.
```
2026-03-16 15:57:21 +00:00
Mervin Praison d58977b956 ```
feat(chat): add platform metadata and icon support

- Updated pyproject.toml version to 0.3.80.
- Enhanced datastore to extract and return platform metadata from sessions.
- Modified chat history API to include session-level metadata (platform, icon).
- Improved frontend styles and added SVG icons for different platforms.
```
2026-03-16 11:06:56 +00:00
Mervin Praison fc5f5de957 ```
feat(datastore): add platform and icon metadata to sessions

Updated session management to include platform and icon metadata
for channel sessions. Adjusted methods in MemoryDataStore and SDKFileDataStore
to accommodate new metadata. Updated frontend to display new metadata.
```
2026-03-16 10:39:34 +00:00
Mervin Praison d46679db7c feat(version): update aiui version to 0.3.78
Bump the version in both `pyproject.toml` and `uv.lock` to reflect the latest changes.
2026-03-16 04:51:42 +00:00
Mervin Praison 64021798be feat(version): update aiui version to 0.3.77
Bump version in pyproject.toml and uv.lock to reflect the new release.
2026-03-15 07:04:37 +00:00
Mervin Praison ba4f9a89a4 feat(dependencies): update version and SDK requirements in pyproject.toml
Updated the version to 0.3.76 and adjusted dependencies for praisonaiagents
and praisonai. Additionally, improved the event mapping logic in the
PraisonAIProvider to handle new SDK event types and prevent error logging spam.
New tests added for thorough coverage of stream event mappings and handling.
2026-03-13 14:52:21 +00:00
Mervin Praison df0556d6de feat(datastore): add SDK-backed DataStore support
Introduces a new `SDKFileDataStore` to unify session persistence
between AIUI and the SDK, allowing seamless session management.
The CLI default datastore is now set to `sdk`, with fallback to
JSON if the SDK is not available. Updates to configuration and
tests have been made to reflect this change.
2026-03-13 13:18:54 +00:00
Mervin Praison aa4e633912 feat(server, frontend): update version and add toolCalls support
- Bump version to 0.3.74 in `pyproject.toml`
- Enhance `ChatArea` and `types` to include `toolCalls` support
- Modify server logic to collect and persist tool calls in messages
- Update frontend assets for compatibility and improved tooling
2026-03-13 11:41:43 +00:00
Mervin Praison 0d3e084cc0 feat(release): bump version to 0.3.73 and enhance SSE tool call tests
- Updated pyproject.toml to reflect version change.
- Enhanced server.py to use an effective style variable for plugins.
- Revised index.html to simplify and remove anti-flicker scripts.
- Added comprehensive integration tests for tool call events in test_tool_call_parity.py.
2026-03-13 09:21:34 +00:00
Mervin Praison 7c5d0601cb feat(chat): enhance tool call handling and display
- Updated `ChatArea` to upsert tool calls by `tool_call_id`
- Enhanced `ToolCallDisplay` to show visual indicators for running status
- Added support for additional tool call properties: description, icon, and step number
- Improved result formatting display logic in `ToolCallDisplay`
- Incremented version in `pyproject.toml` to 0.3.72
2026-03-13 08:35:50 +00:00
Mervin Praison 28c7b93857 feat(chat): improve event handling and deduplication in chat feature
Enhanced the chat feature by adding deduplication for tool call events
to prevent duplicate broadcasts. Improved handling of tool call events
with complete arguments and refined event emission logic to reduce
flooding in the UI. Updated version in pyproject.toml to 0.3.71.
2026-03-13 07:39:00 +00:00
Mervin Praison f918d71516 feat(chat): enrich tool event payload with enhanced display metadata
Added functionality to `_enrich_tool_payload` in `chat.py` to
provide human-readable icons, labels, and descriptions for tool
events. This allows sharing a single source of truth for tool
display between the CLI and AIUI. Updated frontend handling in
`chat.js` to use enriched data for better user experience.
2026-03-13 00:02:55 +00:00
Mervin Praison f20d6d768a feat(version): bump version to 0.3.68 and add approval option
Updated version in pyproject.toml and uv.lock.
Added "approval" setting to PraisonAIProvider to enable auto-approval in sandboxed server contexts.
2026-03-12 23:52:38 +00:00
Mervin Praison 96001a556d feat(version): update version to 0.3.66 and enhance assistant instructions
Updated the version in `pyproject.toml` and `uv.lock` to 0.3.66.
Enhanced assistant instructions for clearer guidance on tool access
and multi-step task completion.
2026-03-12 17:37:10 +00:00
Mervin Praison 0e36b46ed8 feat(dependencies): update version and extras for praisonaiagents
Bump version of aiui to 0.3.65 and include "search" extra in
praisonaiagents dependency to enhance functionality.
2026-03-12 16:45:12 +00:00
Mervin Praison 422749b3de feat(server): add channel status and runtime details to overview API
Updated the API overview to include loaded features, channels info,
runtime type, and configuration details. Incremented version to 0.3.64.
Also added a status endpoint for CLI parity.
2026-03-12 11:07:54 +00:00
Mervin Praison 0908b8f8e8 fix: JSONFileDataStore respects AIUI_DATA_DIR for persistent sessions
On Fly containers (AIUI_DATA_DIR=/data), sessions are now stored at
/data/sessions/ which is on the persistent Fly Volume. Previously
sessions defaulted to ~/.praisonaiui/sessions/ (ephemeral storage)
and were lost on container restarts.

Matches the pattern already used by config_store.py.
2026-03-12 01:13:28 +00:00
Mervin Praison 39538364bd feat(channels): enhance Slack token resolution and update dependencies
- Updated version to 0.3.63 in pyproject.toml and uv.lock.
- Changed discord.py dependency to include voice support.
- Added a static method to resolve Slack app token from config or env var.
- Refactored Slack token retrieval logic in ChannelsFeature class.
2026-03-12 01:07:28 +00:00
Mervin Praison df6c2c970a docs(configuration): enhance environment variable vs config file section
Added a comparison table in the configuration documentation to clarify
the benefits of using environment variables over config files. Updated
version number in pyproject.toml and uv.lock to 0.3.62. Added handling
for Slack app_token in channels.py, and made minor adjustments to chat
and integration features for better stability and clarity.
2026-03-12 00:59:52 +00:00
Mervin Praison 3b59fcef87 feat(app): add error handling for agent registration
- Implemented a try-except block to handle exceptions during agent
  registration, allowing the process to continue without failure.
- Updated version in pyproject.toml and uv.lock to 0.3.61.
- Removed the Dashboard layout component in App.tsx as it is now
  handled by a plugin.
- Set 'reflection' to False in channels and jobs features for consistent
  behavior.
2026-03-11 22:35:20 +00:00
Mervin Praison 4db634eae3 feat(docs): update README and quickstart documentation
Enhanced the README and quickstart guides to better reflect the
capabilities and usage of PraisonAI, including installation steps,
example configurations, and detailed instructions for deploying
the AI dashboard and chat mode. Improved clarity and added
new sections for ease of navigation.
2026-03-11 20:35:51 +00:00
Mervin Praison 5c007a7f9a feat(branding): add logo and branding configuration
- Introduced `set_branding` function to allow configuration of
  sidebar branding (title and logo).
- Updated `DashboardLayout` to display the logo alongside the title.
- Enhanced site configuration to include logo property.
- Version updated to 0.3.60 for branding changes.
2026-03-11 20:24:48 +00:00
Mervin Praison 47266fc3e3 feat(app): add full chat example with agents and feature explorer
Introduced a new example application demonstrating the use of agents
(Researcher, Writer, Coder) and a custom Feature Explorer page
within the dashboard. Updated main app to include agent registration
and streamlined the app structure for improved usability.
2026-03-11 20:12:28 +00:00
Mervin Praison 6ff6883994 feat(docker): update Docker configuration for PraisonAIUI deployment
- Modified Dockerfile to enhance deployment process, including new environment variables and installation method for Python packages.
- Updated .dockerignore to exclude additional files and directories.
- Incremented project version in pyproject.toml.
- Streamlined feature usage by removing unused tools from the resolver in channels.py and providers/__init__.py.
- Expanded test coverage in test_runner.py to include more endpoints and health checks.
2026-03-11 13:45:32 +00:00
Mervin Praison 4254283d14 docs(features): add integration analysis and standardization verification
Added detailed documentation for integration analysis and standardization verification processes. This includes acceptance criteria, current state assessment, gap analysis, and remediation plans to enhance understanding and facilitate implementation.
2026-03-11 11:40:45 +00:00
Mervin Praison b4f37545ac feat(docker): add Docker support with deployment documentation
- Introduced a Dockerfile for building and running the AIUI application.
- Added a .dockerignore file to exclude unnecessary files.
- Created detailed deployment documentation to guide users on setting up the application using Docker.
- Improved overall structure and organization of features in the source code for better maintainability.
2026-03-11 09:02:45 +00:00
Mervin Praison afab9ebb47 feat(docs, cli, guardrails): enhance CLI documentation and guardrails feature
Updated `cli.md` to include detailed options for scheduling and guardrails commands. Improved overall clarity in `feature-inventory.md` reflecting CLI command support. Added new helper methods in `guardrails.py` for CLI command registration. Bumped project version to `0.3.55` in `pyproject.toml`.
2026-03-11 07:38:45 +00:00
Mervin Praison 6ac8325f7a feat(schedules): enhance job execution and delivery process
Updated scheduling logic to include session ID for agent creation.
Introduced `_deliver_result` function to send job results to originating platforms.
Improved logging to track delivery status. Updated version in pyproject.toml.
2026-03-11 07:09:15 +00:00
Mervin Praison f7aba0e10c feat(guardrails): add guardrail management and pre-checks in chat
Implemented guardrail checking mechanism in chat feature, allowing
blocking of messages based on violations. Added API endpoints for
deleting guardrails and enhanced the GuardrailManager to handle
deletion. Updated relevant tests to cover new functionality.
2026-03-10 18:08:27 +00:00
Mervin Praison be13b07709 feat(agent): update agent registration and retrieval methods
- Changed `register_agent` and `unregister_agent` to use agent IDs instead of names for better tracking and management.
- Updated the `get_agent` method to reflect the use of agent IDs.
- Added defensive serialization in agent responses to ensure JSON safety.
- Enhanced websocket route for log streaming.
- Incremented version to 0.3.52 in `pyproject.toml`.
2026-03-10 14:23:46 +00:00
Mervin Praison 0388bc1d74 feat(gateway): add standalone gateway for minimal bot management
Introduced a new `StandaloneGateway` class that allows agent registration
and management without requiring the full `praisonai` wrapper. This
facilitates the use of channels and bots in environments where the
wrapper may not be available, improving flexibility and reducing
dependencies. Updated project dependencies and modified existing code
to integrate the new gateway functionality.
2026-03-10 11:04:40 +00:00
Mervin Praison 6691d4a0df feat(docs): enhance attachments documentation with processing details
Updated the chat attachments documentation to include automatic file
processing and detailed instructions on how uploaded files integrate
with agent prompts. Added processing information for different file
types and usage examples.
2026-03-10 07:53:34 +00:00
Mervin Praison 67b1286c67 docs: update documentation for unified runtime configuration and changes
- Added details on unified runtime config at ~/.praisonaiui/config.yaml.
- Updated API testing instructions to reflect persistence of config changes.
- Documented new "Run" button functionality on dashboard for agents.
- Included details on hot-reload feature and its relationship to config persistence.
2026-03-10 06:43:54 +00:00
Mervin Praison ccf86c2f8b feat(persistence): unify YAML persistence under a single config file
Migrate individual YAML files to a unified `config.yaml` structure for
simplified data management. Update persistence functions to load and
save data directly from sections within this config file, improving
consistency and reducing redundancy.
2026-03-09 20:45:26 +00:00
Mervin Praison 2da3150cce feat(persistence): add YAML persistence for feature states
Implement shared YAML persistence helpers to load and save feature
states. The features now can retain their configurations across server
restarts. Updated the channels and runtime config to utilize this
persistence mechanism. Version bumped to 0.3.46.
2026-03-09 20:41:20 +00:00
Mervin Praison 9d3d3b4d74 feat(api): enhance channel status management and add guardrail registration
- Updated channel status to use a combination of bot status and task completion.
- Enhanced the guardrail registration process to support LLM-based guardrails.
- Updated project version to 0.3.45.
- Added comprehensive integration tests for new features and functionalities.
2026-03-09 20:30:05 +00:00
Mervin Praison d65818f423 feat: introduce unified YAML config store for PraisonAIUI
Added a new YAMLConfigStore class that serves as a central configuration
manager for agents, skills, and channel states. It supports atomic writes,
legacy migration from JSON, and provides a structured API for managing
configuration data. This feature enhances the overall flexibility and
usability of the application.
2026-03-09 20:18:17 +00:00
Mervin Praison 54ff4275c2 feat(version): update version to 0.3.43 and refine dependencies
Updated the project version in `pyproject.toml` to 0.3.43.
Refined the dependency constraints for `markitdown` based on Python version.
Added support for new package versions in `uv.lock`, including `aiohappyeyeballs` and `aiohttp`.
Modified the initialization of `PraisonAIProvider` to include `self_reflect` attribute.
2026-03-09 19:16:02 +00:00
Mervin Praison 7432af0662 fix: SPA navigation content swap — remove duplicates, anti-flicker cleanup
- Added spaNavigating guard to prevent MutationObserver loadContent()
  from racing with SPA navigateToContent()
- Use querySelectorAll to remove ALL old data-aiui-plugin articles
- Always remove anti-flicker CSS after content loads (prevents blank page)
- navigateToContent now removes ALL [data-aiui-plugin] elements before
  inserting new content, preventing duplicate H1s and stale ToC
2026-03-09 17:51:02 +00:00
Mervin Praison 68cdea1216 feat: implement true SPA navigation — no more full page reloads
Rewrote nav-intercept.js to use true SPA content swap:
- Captures native History.prototype.pushState BEFORE React Router patches it
- Intercepts sidebar clicks in capture phase on document (before React's
  event delegation on #root) with stopPropagation()
- Updates URL via native pushState (React Router can't detect it)
- Dispatches aiui:navigate custom event for content-loader.js swap
- Handles browser back/forward via popstate listener

Also:
- content-loader.js now updates page title during SPA navigation
- Improved retry robustness in navigateToContent()
2026-03-09 16:32:41 +00:00
Mervin Praison 743a715795 docs(protocol-architecture): update agent registration and manifest requirements
Expanded documentation on the agent registration API, detailing the new
method using the Protocol ABC. Added important notes on frontend
manifest requirements and common pitfalls to ensure proper
functionality. Updated related example integration scripts to
reflect these changes.
2026-03-09 14:42:46 +00:00
Mervin Praison bdabbcf9eb feat(protocol-architecture): implement SDK-first feature management strategy
Added a new protocol management architecture that enforces an SDK-first
approach for feature modules. Each feature now defines a `FeatureProtocol`
ABC, with fallback mechanisms for simplified management. Updated
documentation in `docs/features/protocol-architecture.md` to reflect
the new protocols and usage guidelines.
2026-03-09 13:50:25 +00:00
Mervin Praison 704843f7e5 feat(docs): add agent tools and reflection documentation
Enhance documentation for agent tool resolution, including YAML configuration
and CRUD API details. Introduce `ToolResolver` usage for defining agent tools
from multiple sources in the gateway chat and concepts documents.

fix(memory): update memory manager initialization fallback

Change memory manager initialization to prioritize `SDKMemoryManager`,
falling back to `SimpleMemoryManager` if SDK initialization fails.

feat(nodes): implement automatic local node registration

Add functionality to auto-register local node information to ensure the
Nodes page is populated and local instance status is accurately reflected.

style(cli): resolve output directory path based on app file location

Update CLI behavior to correctly resolve output directory relative to
the app file's directory to mitigate stale build issues.

chore(tests): enhance unit tests for protocol fixes

Add comprehensive unit tests to cover recent protocol fixes and ensure
reliability of the changes made.

chore(version): bump version to 0.3.39 in pyproject.toml

Update project version in `pyproject.toml` to reflect the latest changes
and improvements.
2026-03-09 13:07:20 +00:00
Mervin Praison 3228af6eec feat(features): add channel-to-chat bridge for real-time messaging
Implement a bridge for connecting channel bot conversations (Slack, Discord, Telegram) to the Chat UI. This feature includes message broadcasting, history persistence, and dedicated session handling for each channel. Documentation has been added to describe the architecture and performance characteristics.
2026-03-09 06:42:03 +00:00
Mervin Praison ba6b17c1ed feat(server): enhance static file serving with WebSocket support
Updated the static file serving to gracefully handle WebSocket requests
instead of crashing. The version is also bumped to 0.3.35 in
pyproject.toml and uv.lock files.
2026-03-09 04:41:51 +00:00
Mervin Praison be20a563dd feat(release): bump version to 0.3.34
Updated the version to 0.3.34 in pyproject.toml and uv.lock.
Modified tracing.py to import ActionEvent instead of Trace.
Enhanced channels.js to clarify optional fields in the UI.
2026-03-08 08:20:35 +00:00
Mervin Praison 1966a2ea87 feat(channels): enhance bot lifecycle management and update version
- Updated version to 0.3.33 in pyproject.toml.
- Improved bot lifecycle tracking in channels.py with local bot management.
- Refactored `_sync_running_status` and `_start_channel_bot` for better clarity and functionality.
2026-03-08 07:00:07 +00:00
Mervin Praison 1f79afb30d feat(channels): update channels feature with new gateway integration
- Bumped version in pyproject.toml to 0.3.32.
- Enhanced channels.py to add a test route and improve gateway status syncing.
- Refactored commands and added error handling for starting/stopping bot instances.
2026-03-08 06:18:16 +00:00
Mervin Praison e175bf74cd fix: eliminate page flash with inline dark background
Three-layer fix:
1. Inline style='background:#0f172a' on <html> and <body> — this is the
   very first thing the browser paints, before ANY CSS files load.
   Prevents the white/transparent frame between page loads.
2. Strengthened anti-flicker CSS: now hides ALL #root children (not just
   main.flex-1 > div), preventing React's debug text from flashing.
3. Nav-intercept overlay now appears instantly with opacity:1 (no fade
   transition), eliminating the ~100ms gap where the flash was visible.
2026-03-08 05:59:17 +00:00
Mervin Praison 5ee14ff110 fix: add cache-busting to plugin JS imports
Both index.html inline loader and plugin-loader.js now append ?v=<timestamp>
to plugin import URLs. This prevents browsers/CDN from serving stale cached
versions of plugin JS files (like the old SPA version of nav-intercept.js
that was still being served after deployment).
2026-03-08 00:40:08 +00:00
Mervin Praison 25e48a96b7 feat(health): add shared gateway health helpers for better connectivity checks
Introduced `_gateway_helpers.py` to centralize gateway connectivity
checks across various features. This reduces code duplication and
ensures consistent handling of gateway health responses. Updated
health methods in multiple features to utilize the new helper.
Bumped version in `pyproject.toml` to 0.3.31.
2026-03-08 00:37:46 +00:00
Mervin Praison d0c8c94f4e fix: replace SPA approach with overlay-based full page reload
SPA approach failed because React 18 uses useSyncExternalStore to
monitor history — even native History.prototype.pushState triggers
React Router's re-render and DOM unmount.

New approach: keep full page reload (which works correctly) but add
a dark overlay (#0f172a) before navigation starts. The overlay covers
the viewport instantly, hiding the transition gap between old page
unload and new page render. This eliminates the black flash visually
while keeping the proven full-page-load architecture.
2026-03-08 00:28:39 +00:00
Mervin Praison 5e57577c53 fix: use native History.prototype.pushState to bypass React Router
Root cause: calling the patched history.pushState triggered React Router's
internal listener, causing it to unmount the entire DOM (<div id='root'></div>
becomes empty). This caused the persistent black screen on sidebar clicks.

Fix:
- nav-intercept.js: save History.prototype.pushState before React patches it,
  use nativePushState.call(history, ...) for SPA navigation
- nav-intercept.js: add stopImmediatePropagation to prevent React from
  seeing sidebar click events
- nav-intercept.js: normalize all paths with trailing slash
- content-loader.js: add 100ms retry if main.flex-1 missing (React unmount
  recovery), fallback to #root if still absent
- content-loader.js: skip homepage paths (handled by homepage.js)
- content-loader.js: remove anti-flicker CSS after SPA navigation
2026-03-08 00:24:36 +00:00
Mervin Praison 20cf000405 feat(features): add evaluation and accuracy monitoring feature
This commit introduces a new evaluation feature for PraisonAIUI, allowing
for agent evaluation and accuracy monitoring. The feature surfaces evaluation
scores, judge results, and quality metrics via a dedicated API. Additionally,
several other features including guardrails, telemetry, tracing, and security
are added or updated, enhancing the overall functionality. The project version
is updated to 0.3.30.
2026-03-08 00:08:46 +00:00
Mervin Praison 4b968aaf71 feat(gateway): enhance integration with gateway agents
Added functionality to validate and utilize gateway-registered agents across different features. Enhanced health checks, configuration responses, and job execution logic to include information about gateway connectivity and available agents. Updated version in `pyproject.toml` to 0.3.29.
2026-03-07 23:44:22 +00:00
Mervin Praison 34c1404c99 feat(agents): improve agent loading, syncing, and copy functionality
- Enhanced error handling during agent saving and loading with logging.
- Added support for syncing loaded agents to the gateway.
- Improved fallback mechanism to retrieve agents from the gateway.
- Updated agent creation logic to copy all fields except timestamps.
- Merged gateway-registered agents when listing agent definitions.
- Bumped version to 0.3.28 in pyproject.toml.
2026-03-07 22:28:19 +00:00
Mervin Praison c04713c5ce fix: SPA navigation - eliminate black screen on sidebar click
- nav-intercept.js: rewrite from full page reload (window.location.href) to
  SPA-style navigation using pushState + aiui:navigate custom event
- content-loader.js: add navigateToContent() for SPA content swapping
- homepage.js: add aiui:navigate listener for home transitions
- topnav.js: fix tab auto-switch-back with userClickedTab flag,
  fix sidebar highlighting with data-aiui-active-sidebar attribute

Root cause: nav-intercept.js forced window.location.href on every
sidebar click, causing full page reload → 1s black screen.
2026-03-07 22:16:06 +00:00
Mervin Praison 53b370a9ce fix: eliminate UI flickering, blank homepage, black flash, and sidebar highlighting
- index.html: add anti-flicker CSS in head, remove 300ms delay, call notify() immediately
- homepage.js: move setHomepageMode(true) after article creation, use opacity not display:none
- content-loader.js: move setContentMode(true) after article creation, use opacity/absolute
- topnav.js: URL-based sidebar highlighting via highlightActiveSidebarItem()
- server.py: update anti-flicker CSS to match index.html pattern
2026-03-07 22:01:04 +00:00
Mervin Praison 4fe06d46b0 feat(chat): enhance chat feature with persistent datastore integration
Added functionality to persist user messages to a datastore in the ChatManager.
Modified chat history retrieval to prioritize the datastore and added callbacks
for run cancellation. Other improvements include sending responses and handling
memory updates within the chat context. Updated version number to 0.3.27.
2026-03-07 20:40:05 +00:00
Mervin Praison da2dd8eabe feat(app): enhance three-column feature explorer with gateway mode
Added functionality for a gateway mode, allowing real agent execution
and WebSocket interaction. Updated usage instructions and introduced
multiple agent definitions for enhanced user experience. Improved
fallback to standalone mode for REST APIs only.
2026-03-07 18:15:50 +00:00
Mervin Praison ad88efa17d feat(explorer): add three-column feature explorer demo
Introduced a new three-column layout in the demo application, showcasing
clickable feature and endpoint lists, a live request/response activity log,
and formatted JSON output. Updated version in pyproject.toml and modified
dashboard.js to include the new explorer view.
2026-03-07 17:53:59 +00:00
Mervin Praison 9072498110 docs(api): Update features API documentation with new endpoints
Added comprehensive details for new feature endpoints including
memory context retrieval, TTS functionalities, marketplace actions,
code execution, PWA enhancements, and device pairing capabilities.
2026-03-07 07:04:56 +00:00
Mervin Praison b5e8bfc39e feat(docs): add comprehensive feature documentation updates
Added new documentation for various features including attachments,
browser automation, comparison with OpenClaw, and more. This totals
to 13 new or modified files with extensive content to enhance
user understanding and usage of the platform's capabilities.
2026-03-06 20:54:40 +00:00
Mervin Praison dd7323ef02 feat(images, features, tests): add chat attachments feature and assets
- Introduced a new chat attachments feature enabling file uploads for agent context.
- Added necessary binary images to the documentation.
- Updated `pyproject.toml` to reflect version change.
- Implemented attachment management with size and type configurations.
- Enhanced existing features and tests to integrate with the new attachments functionality.
2026-03-06 20:32:20 +00:00
Mervin Praison eea80564de feat(examples): add AIUIGateway integration example with full execution
This example demonstrates the PrasionAIUI Gateway integration using the
AIUIGateway, featuring real agent execution, WebSocket streaming, a
full dashboard, and live agent interaction from the browser. It also
includes agent definitions and custom analytics page registration.
2026-03-06 15:50:44 +00:00
Mervin Praison fe7d1f47be feat(api): enhance node and session endpoints, update dashboard UI
- Added new API routes for listing instances and heartbeat.
- Improved session ID handling to accommodate list of strings or dicts.
- Updated dashboard UI, renaming 'Test All Features' to 'Feature Inspector'
  and enhancing its description for better clarity.
- Bumped version to 0.3.23 in pyproject.toml.
2026-03-06 15:06:58 +00:00
Mervin Praison 1c044cbbfc feat(dashboard): enhance dynamic dashboard example application
Updated the dashboard example to illustrate a protocol-first page registration system. Enhanced documentation for better understanding and added new features, including custom page registration via the API. Updates also include a version bump in `pyproject.toml` to 0.3.22 and various route improvements across multiple files.
2026-03-06 14:32:15 +00:00
Mervin Praison 9f76895009 feat(docs): Add comprehensive API and dashboard documentation
This commit introduces extensive documentation for the component API,
dashboard features, and quick start guides. These additions cover
function usage, layout options, and methods to register pages, enhancing
the developer experience and improving onboarding for new users.
Additionally, minor adjustments were made to existing workflow instructions.
2026-03-06 13:50:46 +00:00
Mervin Praison 535969533e feat(dashboard): overhaul dynamic dashboard example application
Refactored the example dashboard application to demonstrate a settings-driven
interface showcasing all 16 features of PraisonAIUI. Reduced complexity by
removing hardcoded elements. Added custom page registrations for analytics
and metrics, while significantly improving code structure and maintainability.
2026-03-06 13:13:55 +00:00
Mervin Praison f67f5f646b feat(docs): add comprehensive API testing guide
Included a detailed API testing guide in `docs/api/testing.md`, providing
curl commands and descriptions for testing all 16 PraisonAIUI feature APIs.
This serves as a resource for developers to quickly understand and test
the available API endpoints. Also updated example usage in `examples/python/15-dashboard-test/app.py` and made minor adjustments in other files.
2026-03-06 12:37:14 +00:00
Mervin Praison 728a0791b0 feat(docs): update API documentation and navigation structure
- Refactored navigation in `aiui.template.yaml` for improved
  organization, adding an "API Reference" tab.
- Updated `features-api.md` with new endpoints and examples,
  including enhanced approval management and session handling features.
- Improved clarity and consistency in API request/response examples.
2026-03-06 12:06:41 +00:00
Mervin Praison 6d0853a003 Update README.md 2026-03-06 10:05:12 +00:00
Mervin Praison 980ad9ff26 docs(api): update API documentation for new features and endpoints
This commit adds comprehensive documentation for new API endpoints related to jobs, schedules, and skills, including examples of request and response payloads. Additionally, it updates the count of built-in features and improves the overall structure and clarity of the API docs.
2026-03-06 09:53:40 +00:00
Mervin Praison 99697b4008 feat(jobs): add async job management feature for PraisonAIUI
This commit introduces a new feature for submitting, monitoring, and managing async jobs in PraisonAIUI. It adds a new `jobs.py` module that provides API endpoints for job operations and integrates with the existing architecture, enabling users to handle jobs effectively. Additional updates include plugins to the frontend for job management functionalities.
2026-03-06 09:17:49 +00:00
Mervin Praison c818986050 feat(workflows): add gap implementation prompts and new features
Added a comprehensive gap implementation prompts document outlining tasks
for the development of the Channel Management and Scheduler dashboard tabs
in PraisonAIUI. Included analysis, implementation steps, and verification
requirements to enhance user experience and functionality within the
application. Additionally, updated several API and frontend components to
support the new features.
2026-03-06 08:42:36 +00:00
Mervin Praison 1e149a4757 feat(dashboard): update real dashboard with live metrics and new agents
- Enhanced the Real Agent Dashboard to support live metrics.
- Introduced real PraisonAI agents for enhanced interaction.
- Updated navigation and documentation to reflect the changes in examples.
2026-03-06 07:51:33 +00:00
Mervin Praison f40cf42345 feat(docs): enhance examples documentation with structured references
Added detailed references for Python examples, outlining each example's unique concept and run instructions for better clarity and usability. Updated the examples README for improved navigation.
2026-03-06 01:28:37 +00:00
Mervin Praison 7aaebf9883 refactor(examples): clean up demo dashboards and improve structure
Removed outdated demo data functions in the full dashboard example and consolidated shared seed data usage. Updated the README to reflect changes in dashboards and documentation structure. Reduced overall lines of code by eliminating unnecessary files and code blocks.
2026-03-06 01:12:49 +00:00
Mervin Praison 70925f584b fix: black screen on navigation — restore hidden main children
Homepage plugin set display:none on main children but never restored
them when navigating to other pages via SPA routing.
2026-03-06 00:59:55 +00:00
Mervin Praison fe280339bb fix: extend heading visibility fix to all h1-h6 levels
Subtitles like 'init' on CLI page were invisible due to gradient/opacity.
Now all heading levels get solid white color override.
2026-03-06 00:53:38 +00:00
Mervin Praison 1ba36e2a0e fix: mermaid legibility + title visibility (Mintlify-inspired)
- Vibrant teal (#0d9488) node backgrounds with white text for max contrast
- CSS force-override for node labels (color/fill #ffffff !important)
- Fixed faded h1 title by overriding gradient/opacity/-webkit-text-fill-color
- Dark container background (rgba 0f172a 0.5) for diagram framing
2026-03-06 00:50:41 +00:00
Mervin Praison b734a34b1b fix: eliminate plugin flickering via idempotent onContentChange
- mermaid.js & toc.js now track URL and only tear down on navigation
- Repeated notify calls skip if content already rendered
- Reduced staggered notify from 3 to 2 calls (300ms + 3s)
2026-03-06 00:40:20 +00:00
Mervin Praison 36b929fd3f fix: mermaid regex missing 'D' + premium dark theme + staggered timing
Root cause: isMermaidSyntax regex [TBLR]{2} didn't match 'TD' (most common
mermaid direction). Fixed to (TD|TB|BT|LR|RL).

Also:
- Premium transparent dark theme with teal/purple/emerald palette
- Hover glow effects on diagram containers
- Staggered notify timing (300ms/1.5s/4s) for CDN latency
- Added block-beta and requirement to mermaid syntax patterns
2026-03-05 17:39:52 +00:00
Mervin Praison 7803449971 docs: update provider documentation and protocol overview
Enhanced the provider protocol section in `providers.md` with updated
architecture diagrams and descriptions. Incremented version in
`pyproject.toml` to 0.3.15. Reflected changes in the integration
process in `integration.py`, incorporating WebSocket setup and
pluggable provider system. Reduced redundant comments and
improved clarity of the codebase.
2026-03-05 17:33:52 +00:00
Mervin Praison 961aa1109b fix: avoid React DOM reconciler crashes in plugins
All plugins now use hide+append pattern instead of replaceWith/innerHTML:
- homepage.js: hides debug content via display:none, appends docs article
- toc.js: hides static Overview/Usage links, appends dynamic headings
- mermaid.js: hides code block, inserts SVG diagram as sibling

This resolves 'Failed to execute removeChild on Node' errors.
2026-03-05 17:22:56 +00:00
Mervin Praison dd2b847664 fix: embed plugin-loader inline, fix mermaid detection for Prism.js
Root causes fixed:
- Plugin-loader as external type=module wasn't executing
- Mermaid plugin now detects Prism.js-rendered blocks via syntax heuristic
- Also adds toc.js to replace hardcoded Overview/Usage links
2026-03-05 17:19:44 +00:00
Mervin Praison a1c060f61e feat: add dynamic table of contents plugin (toc.js)
Replaces the hardcoded 'Overview'/'Usage' links in the 'On this page'
sidebar with actual headings extracted from the rendered markdown content.
Handles SPA navigation by re-generating on content changes.
2026-03-05 17:08:16 +00:00
Mervin Praison b142dde043 ci: trigger fresh deployment 2026-03-05 17:03:49 +00:00
Mervin Praison ec27a8906f feat: add frontend plugin system with mermaid, fetch-retry, mkdocs-compat, homepage plugins
- plugin-loader.js: core MutationObserver-based plugin loader
- mermaid.js: renders mermaid code blocks as SVG diagrams via CDN
- fetch-retry.js: exponential backoff retry for .md/.json fetches
- mkdocs-compat.js: transforms MkDocs Material syntax to standard HTML
- homepage.js: replaces hardcoded debug landing page with docs/index.md
- compiler.py: _copy_plugins() generates plugins.json from YAML config
- models.py: add plugins field to SiteConfig (defaults: all built-in)
- index.html: add plugin-loader.js script tag
2026-03-05 16:52:28 +00:00
Mervin Praison 2b3541087d 14 2026-03-05 16:31:08 +00:00
Mervin Praison faace20410 fix: SEO title and meta tags - change from generic 'Documentation' to 'PraisonAIUI'
- Update <title> from 'Documentation' to 'PraisonAIUI'
- Update meta description with actual product description
- Add og:title and og:description meta tags
2026-03-05 16:27:35 +00:00
Mervin Praison 68bc2722f8 push 2026-03-05 16:23:28 +00:00
Mervin Praison ad24f6d32f u 2026-03-05 16:21:51 +00:00
Mervin Praison 6b028e1313 fix: SPA routing on GitHub Pages + heading color in dark mode
- Add 404.html (copy of index.html) so GitHub Pages serves the SPA
  shell for all routes instead of a 404 page
- Add CSS override to make prose headings white in dark mode
  (fixes near-invisible heading text on dark backgrounds)
- Fix remaining E501/F401 lint errors in server.py, themes.py,
  providers/__init__.py
2026-03-05 16:19:38 +00:00
Mervin Praison 1c1a749472 fix: remove needs:python from docs job - pre-existing lint failures block deploy 2026-03-05 16:09:31 +00:00
Mervin Praison 0d0551be50 feat: replace MkDocs with AIUI for GitHub Pages deployment
- Update CI to use 'aiui build' instead of 'mkdocs build'
- Add GitHub Pages migration guide docs
- Populate .agent/workflows/information.md with project reference
- Add GitHub Pages entry to mkdocs.yml nav
2026-03-05 16:08:01 +00:00
Mervin Praison cd82e923ae u 2026-03-05 15:46:37 +00:00
Mervin Praison 4b6ef41fa1 u 2026-03-05 15:32:49 +00:00
Mervin Praison 3a7495dc37 u 2026-03-05 12:19:24 +00:00
Mervin Praison 3083880f55 u 7 2026-03-05 07:07:28 +00:00
Mervin Praison 004002e655 u 5 2026-03-05 06:32:47 +00:00
Mervin Praison 1eec8acf99 u 10 2026-03-04 17:10:18 +00:00
Mervin Praison cc43a0e25d u 9 2026-03-04 16:46:56 +00:00
Mervin Praison c82a2a5419 u 6 2026-03-04 14:21:38 +00:00
Mervin Praison 3c6b31824f u 7 2026-03-04 11:16:28 +00:00
Mervin Praison 2c81895f82 u 6 2026-03-04 10:45:28 +00:00
Mervin Praison 8b612a2498 u 5 2026-03-04 10:27:34 +00:00
Mervin Praison 48c1bc19fa u 4 2026-03-04 07:29:15 +00:00
Mervin Praison 15ecb030ce u 7 2026-03-03 18:31:35 +00:00
Mervin Praison e75e89e3a7 update 2026-03-03 17:49:41 +00:00
Mervin Praison 6bafce544a u 2026-03-03 16:44:45 +00:00
Mervin Praison 960e384b15 u 3 2026-03-03 15:45:15 +00:00
Mervin Praison 6b737a3d1e u 2026-03-03 14:51:28 +00:00
Mervin Praison 562a20b6e9 u 2026-03-03 12:56:05 +00:00
Mervin Praison b9783ac844 update 2026-03-03 12:47:08 +00:00
Mervin Praison 55c00f028f u 2026-03-03 12:37:38 +00:00
Mervin Praison 57ec16f709 chore: Bump aiui package version to 0.2.7. 2026-01-29 06:49:49 +00:00
Mervin Praison c0aabc1647 fix: Dev dashboard now respects YAML theme by default
Added 'Use YAML Theme' checkbox to dev dashboard toolbar (checked by default).
When checked, theme/radius/darkMode from YAML are used instead of dropdown overrides.
Users can uncheck to use dashboard theme controls.

Fixes issue where YAML theme changes weren't reflected in dev dashboard.
2026-01-29 06:35:59 +00:00
Mervin Praison da13157d9b feat: Add 4 new widget types and update corporate example
NEW WIDGETS:
- Progress: Progress bar with label and percentage
- Announcement: Alert banner with info/warning/success types
- RecentPosts: List of recent posts with dates
- BadgeList: Tag/badge display widget

CORPORATE EXAMPLE UPDATED:
- hero zone: Announcement widget
- rightSidebar: Toc, StatsCard, Progress, QuickLinks, RecentPosts, BadgeList
- footer: Newsletter, SocialLinks, Copyright

Frontend bundle: 421KB (10 widget types total)
2026-01-29 06:27:58 +00:00
Mervin Praison 879690a89f fix: Rebuild frontend bundle with widget components
- Remove problematic resizable.tsx component
- Fix unused Separator import in widgets.tsx
- Update templates/frontend/assets/ with rebuilt bundle
- Bundle now includes StatsCard, QuickLinks, Newsletter, etc.
2026-01-29 06:16:39 +00:00
Mervin Praison c22ab42864 docs: Add Widget Zones documentation
- Create docs/features/widget-zones.md with full zone/widget docs
- Update docs/concepts/configuration.md with Widget Zones section
- Document 8 zones and 6 built-in widgets
- Add FlexibleLayout to layouts table
2026-01-29 06:13:35 +00:00
Mervin Praison bbd3a91956 fix: Integrate widget zones with frontend runtime
- Compiler now outputs zones to ui-config.json
- Add 6 inline widget components (StatsCard, QuickLinks, Newsletter, HeroBanner, Copyright, SocialLinks)
- Update Toc to render rightSidebar zone widgets
- Update all layouts to support zones (hero, leftSidebar, rightSidebar, bottomNav)
- Add FlexibleLayout case to renderLayout
2026-01-29 06:12:15 +00:00
Mervin Praison 56b79c2ae3 feat: WordPress-style widget zones system
- Add WidgetConfig, ZonesConfig to schema
- Create FlexibleLayout with 8 zones (header, topNav, hero, leftSidebar, main, rightSidebar, bottomNav, footer)
- Add 6 widget components: StatsCard, QuickLinks, Newsletter, SocialLinks, Copyright, HeroBanner
- Update examples with zone-based widget configuration
- Auto-install new shadcn components on build
2026-01-29 06:08:13 +00:00
Mervin Praison 68c9fe36f7 Add component dependencies to all examples - each showcases different layouts and components 2026-01-29 06:01:51 +00:00
Mervin Praison 58a9f6c6ed v0.2.6: Auto-download components, 22 theme presets, simplified CI 2026-01-29 05:55:28 +00:00
Mervin Praison cc26bfd54a ci: Trigger MkDocs rebuild 2026-01-29 05:51:22 +00:00
Mervin Praison 3f233931e7 feat: Introduce new UI components and refactor theming to be configurable via Python. 2026-01-29 05:47:56 +00:00
Mervin Praison dd44b23139 fix: Decouple MkDocs deployment from Python CI 2026-01-29 05:39:59 +00:00
Mervin Praison add158e24d feat: Introduce aiui dev command for a live example dashboard and refine template layouts across examples. 2026-01-29 05:11:16 +00:00
Mervin Praison 6e75549c6c feat: Revamp frontend theming with shadcn/ui presets and introduce a comprehensive UI component library. 2026-01-29 04:30:43 +00:00
Mervin Praison 59d294c814 feat: Add a CLI command to serve the built site and update documentation to clarify UI-agnostic component styling. 2026-01-29 03:58:55 +00:00
Mervin Praison 446ce976ef u 2026-01-29 03:22:30 +00:00
Mervin Praison 86c26863b1 feat: Implement plugin system, add i18n and a11y configuration, and expand examples. 2026-01-29 03:19:20 +00:00
Mervin Praison 1a96365c17 Create CNAME 2026-01-29 03:11:25 +00:00
Mervin Praison 821e6f0611 Delete CNAME 2026-01-29 03:11:19 +00:00
Mervin Praison d9ad78b569 Create CNAME 2026-01-28 18:11:58 +00:00
Mervin Praison be1d37c51a update 2026-01-28 18:08:35 +00:00
917 changed files with 180001 additions and 25437 deletions

No files matched your search

@@ -0,0 +1,375 @@
---
description: Comprehensive analysis workflow that produces a detailed GitHub issue — combines deep codebase analysis with issue creation for implementation-ready tickets
---
# Analysis → GitHub Issue Workflow
Deep Analysis → Gap Analysis → Critical Review → Plan → Create GitHub Issue.
> **When to use this:** You need to analyze a feature, integration, or system deeply and produce a GitHub issue that another agent/developer can implement immediately without asking follow-up questions.
> **When NOT to use this:** Use `/analysis` for analysis-only (no issue). Use `/local-fix` if you're implementing yourself.
---
## PRINCIPLES (apply throughout)
- **Agent-centric**: Agents, workflows, sessions, tools, memory, multi-agent safety.
- **Protocol-driven core**: praisonaiagents = lightweight, protocol-first (protocols/hooks/adapters only).
- **DRY**: identify reuse; avoid duplication.
- **No perf impact**: preserve import-time and hot-path; heavy deps optional + lazy.
- **Async-safe + multi-agent safe** by default.
- **Easy for non-developers**: "Few lines of code to do the task!"
- **No competitor names in public surfaces**: Never mention competitor product, company, or project names in GitHub issues, PRs, commit messages, release notes, docs, or any other public-facing content. Refer to capabilities generically (e.g., "self-improving agent pattern", "external agent framework").
---
## CANONICAL PATHS
```
UI Repo: /Users/praison/praisonaiui (praisonaiui)
SDK Core: /Users/praison/praisonai-package/src/praisonai-agents (praisonaiagents)
Docs: /Users/praison/PraisonAIDocs
Extension: src/praisonaiui/*, docs/*, tests/*
```
---
## Phase 1 — Acceptance Criteria
Translate the request into testable criteria:
- API expectations (classes, methods, signatures)
- CLI expectations (commands, flags, help text)
- Documentation expectations (pages, examples)
- Test expectations (unit, integration, smoke, real agentic)
- Performance constraints (import time, hot-path)
---
## Phase 2 — External Research (if applicable)
### 2a. Read official sources
If analyzing an external integration, research from primary sources:
```bash
# Use read_url_content tool for:
# - Official site / announcement pages
# - GitHub README and docs
# - Framework documentation
# - Third-party write-ups
```
**Capture:**
- What is it? Purpose and design goals
- Key terminology and concepts
- Architecture overview
- Current ecosystem state
- References list (all URLs)
### 2b. Clone & analyze external codebase (if applicable)
```bash
git clone <repo-url> ~/<repo-name> --depth=1
ls -la ~/<repo-name>/
```
Key files to read:
- `AGENTS.md` / `README.md` — architecture overview
- Base class files (abstract methods, signatures)
- Factory / registry files (registration pattern)
- Model/config files (data structures)
- Example implementations (minimal + full-featured)
- `pyproject.toml` / `package.json` — dependencies
---
## Phase 3 — PraisonAI Codebase Inventory
### 3a. Inventory with evidence
Go through ALL relevant files, understand current logic end-to-end.
```bash
# UI repo
ls /Users/praison/praisonaiui/src/praisonaiui/
ls /Users/praison/praisonaiui/tests/
ls /Users/praison/praisonaiui/docs/
# Optional cross-check against SDK only when needed
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/
```
**Document:**
- Public APIs: modules/classes/functions and exports
- Protocols/adapters/hooks and extension points
- CLI commands, options, help text
- Integrations (db/observability/tools)
- Tests (unit/integration), fixtures, CI config
- Docs (Mintlify), examples, recipes
Provide: **file paths + key symbols + grep counts + entry points**.
### 3b. Identify DRY opportunities
- Existing abstractions that can be reused
- Duplicated code that should be consolidated
- Existing protocols before creating new ones
---
## Phase 4 — Detailed Analysis
### 4a. Architecture and behavior
- Control flow and data flow
- Concurrency model (sync/async)
- Multi-agent interactions
- Dependency boundaries (core/wrapper/tools)
- Failure modes and error handling
### 4b. Invariants check
Verify these are preserved:
- [ ] Protocol-driven core (no heavy impls in praisonaiagents)
- [ ] Lazy imports (optional deps never at module level)
- [ ] Backward compatible (public API changes need deprecation)
- [ ] Safe defaults (new features opt-in)
---
## Phase 5 — Gap Analysis
Compare acceptance criteria vs current state.
### Checklist
| Area | Current State | Gap | Severity | Impact | Placement |
|------|---------------|-----|----------|--------|-----------|
| Core SDK | | | | | |
| Wrapper | | | | | |
| Tools/plugins | | | | | |
| CLI | | | | | |
| Docs | | | | | |
| Tests | | | | | |
| Exports | | | | | |
| Perf | | | | | |
| Multi-agent + async | | | | | |
### Gap severity levels
- **Critical**: Blocks functionality
- **High**: Significant limitation
- **Medium**: Missing feature
- **Low**: Nice-to-have
---
## Phase 6 — Critical Review
### 6a. Risks and footguns
- API ambiguity or edge cases
- Backward compatibility concerns
- Coupling violations
- Performance regressions
- Concurrency hazards
- Misuse risks
- Operational concerns
### 6b. Mitigation strategies
For each risk, document:
- "Safe by default" recommendation
- Explicit opt-in for dangerous behavior
- Documentation warnings
---
## Phase 7 — Implementation Plan
Step-by-step plan (DO NOT implement):
### 7a. Test-first (TDD)
1. Unit tests for new functionality
2. Integration tests for cross-component behavior
3. Smoke tests for quick validation
4. **Real agentic tests** (REQUIRED):
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are helpful")
result = agent.start("Say hello in one sentence")
print(result) # Must call LLM and produce response
```
### 7b. Implementation order
1. Tests (TDD)
2. Core implementation
3. CLI integration
4. Documentation
5. Verification
### 7c. Files to change/create
| File | Action | Purpose |
|------|--------|---------|
| | | |
### 7d. Verification commands
```bash
# Unit tests
pytest tests/unit/test_<feature>.py -v
# Integration tests
pytest tests/integration/test_<feature>.py -v
# Smoke test
python -c "from praisonaiagents import <Feature>; print('OK')"
# Real agentic test
python examples/<feature>_example.py
```
---
## Phase 8 — Draft GitHub Issue
The issue must be **self-contained**. Another agent must be able to implement by reading only the issue.
### Required sections
```markdown
## Overview
One paragraph: what, why, and the end goal.
## Background
- Purpose and design goals
- Why this is valuable
- Current state / ecosystem
## Architecture Analysis
### Current Implementation
- Key files and their purposes
- Integration points
- Data flow
### Key File Locations
| File | Purpose | Lines |
|------|---------|-------|
## Gap Analysis Summary
### Critical Gaps
| Gap | Impact | Effort |
|-----|--------|--------|
### Feature Gaps
| Feature | Current Support | Gap |
|---------|-----------------|-----|
## Proposed Implementation
### Phase 1: Minimal
Working code example.
### Phase 2: Production
Working code example.
## Files to Create / Modify
### New files
| File | Purpose |
|------|---------|
### Modified files
| File | Change |
|------|--------|
## Technical Considerations
- Dependencies
- Performance impact
- Safety / approval
- Multi-agent safety
## Acceptance Criteria
- [ ] Verifiable checkbox list
## Implementation Notes
### Key Files to Read First
1. `path/to/file.py` (N lines) — purpose
### Critical Integration Points
1. Where X connects to Y
### Testing Commands
```bash
# Copy-pastable commands
```
## References
- [Link](url)
```
---
## Phase 9 — Create GitHub Issue
### 9a. Create via `gh` CLI
```bash
gh issue create \
--repo MervinPraison/PraisonAIUI \
--title "<Type>: <Descriptive Title>" \
--body "<issue body>"
```
**Title formats:**
- `Feature: <What>` — new functionality
- `Analysis: <Topic>` — analysis/research
- `Integration: <External System>` — external integration
- `Fix: <Problem>` — bug fix proposal
### 9b. Verify issue created
```bash
gh issue view <number> --repo MervinPraison/PraisonAIUI | head -20
```
---
## Checklist — Before Creating Issue
- [ ] Acceptance criteria defined and testable
- [ ] All relevant PraisonAI files read (not skimmed)
- [ ] External sources researched (if applicable)
- [ ] Gap analysis completed with severity ratings
- [ ] Critical review identifies risks and mitigations
- [ ] Implementation plan is step-by-step with file list
- [ ] Issue body has working code examples (not pseudocode)
- [ ] All file paths are absolute and verified
- [ ] CLI commands are copy-pastable
- [ ] Acceptance criteria are verifiable (not vague)
- [ ] References section includes all URLs
- [ ] Issue is self-contained — no "see docs" without details
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---------|-----|
| Pseudocode in examples | Use real, runnable code with imports |
| Vague file paths | Use absolute paths |
| Skipping gap analysis | Every gap needs severity + impact |
| Missing real agentic test | Include `agent.start()` test, not just construction |
| No verification commands | Include copy-pastable pytest/python commands |
| Claiming "done" without evidence | Every claim references specific files/symbols |
| Implementing instead of analyzing | This workflow produces issues, not code |
---
## Hard Rules
1. **DO NOT implement** — this workflow produces analysis and issues only
2. **DO NOT claim done** without evidence
3. **Every claim must reference** specific files/symbols
4. **Issue must be self-contained** — implementer needs no follow-up questions
5. **Working code examples required** — no pseudocode
+104
View File
@@ -0,0 +1,104 @@
---
description: analysis
---
You are an expert AI engineer in the PraisonAI ecosystem.
Your job: produce ONLY (1) analysis, (2) review, (3) gap analysis, (4) critical review, (5) plan, (6) proposal.
Do NOT implement. Do NOT write code. Do NOT update docs. Do NOT run tests beyond discovery.
Be precise, evidence-based, and agent-centric.
PRINCIPLES (apply in all analysis/proposals):
- Agent-centric: Agents, workflows, sessions, tools, memory, multi-agent safety.
- Protocol-driven core: praisonaiagents = lightweight, protocol-first (protocols/hooks/adapters only).
- DRY: identify reuse; avoid duplication.
- No perf impact: preserve import-time and hot-path; heavy deps optional + lazy.
- Async-safe + multi-agent safe by default.
- Clear paid upgrade path (support/cloud/services) without restricting core.
- Easy for non-developers. "Few lines of code to do the task!"
CANONICAL PATHS:
- UI Repo: /Users/praison/praisonaiui (praisonaiui)
- SDK Core (reference): /Users/praison/praisonai-package/src/praisonai-agents (praisonaiagents)
- Docs: /Users/praison/PraisonAIDocs (JS: docs/js, Rust: docs/rust)
- Extension points: src/praisonaiui/*, docs/*, tests/*
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MANDATORY PROCESS (NO IMPLEMENTATION)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 1 — Acceptance Criteria
- Translate request into testable criteria: API, CLI, docs, test expectations, perf constraints.
STEP 2 — Repo Inventory (evidence-based)
- Go through ALL relevant files, understand current logic end-to-end.
- Inventory with evidence:
- Public APIs: modules/classes/functions and exports
- Protocols/adapters/hooks and extension points
- CLI commands, options, help text
- Integrations (db/observability/tools)
- Tests (unit/integration), fixtures, CI config
- Docs (Mintlify), examples, recipes
- Provide: file paths + key symbols + grep counts + entry points.
- Identify DRY opportunities.
STEP 3 — Detailed Analysis
- Architecture and behavior: control flow, data flow, concurrency (sync/async), multi-agent interactions, dependency boundaries (core/wrapper/tools), failure modes.
- Highlight invariants: protocol-driven core, lazy imports, optional deps.
STEP 4 — Detailed Review
- Evaluate against principles: agent-centricity, API simplicity, DRY, perf, optional deps + lazy imports, async/multi-agent safety, test coverage, CLI parity, docs clarity.
- Concrete evidence for each judgment.
STEP 5 — Gap Analysis
- Compare acceptance criteria vs current state. Checklist:
- UI Core, CLI, Docs, Tests, Exports, Perf, Multi-agent + async
- Each gap: severity, impact, risk, recommended location (core/wrapper/tools).
STEP 6 — Critical Review
- Risks, footguns, maintenance concerns:
- API ambiguity, edge cases, backward compat
- Coupling violations, perf regressions, concurrency hazards
- Misuse risks, operational concerns
- Mitigation strategies and "safe by default" recommendations.
STEP 7 — Plan
- Step-by-step (do not implement): tests (TDD) → implementation → CLI → docs → verification
- Exact files to change/create. Migration/compat plan. Rollback plan. Verification commands. Perf checks. Multi-agent + async test strategy.
REAL AGENTIC TEST definition (MUST include in every verification plan):
- A "real agentic test" = agent ACTUALLY RUNS and calls the LLM:
1. Create Agent with the feature being tested
2. Call `agent.start("a real task prompt")` — NOT just constructing the object
3. Agent MUST call LLM and produce text response
4. Print full output so dev can see it worked end-to-end
- Example:
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are a helpful assistant")
result = agent.start("Say hello in one sentence")
print(result)
```
- Assert-only object construction = SMOKE TEST, not real agentic test.
- Both smoke AND real agentic tests required.
STEP 8 — Proposal
- Minimal, agent-centric design and API/CLI surface:
- protocols/hooks in core; implementations in wrapper/tools
- Clear defaults and explicit overrides
- Multi-agent resource isolation/sharing
- Error model and observability hooks
- Include: "Simple API" examples, CLI UX, docs outline, paid upgrade path.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
REQUIRED OUTPUT (in order):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1) Acceptance Criteria
2) Inventory (evidence: paths/symbols/exports/grep counts)
3) Detailed Analysis (architecture + flows + invariants)
4) Detailed Review (quality vs principles, evidence-based)
5) Gap Analysis (checklist + severity/impact/placement)
6) Critical Review (risks + mitigations)
7) Plan (step-by-step + file list + verification strategy)
8) Proposal (agent-centric design + API/CLI/docs outline)
Hard rules: DO NOT implement. DO NOT write code. DO NOT claim done. Every claim must reference specific files/symbols.
+228
View File
@@ -0,0 +1,228 @@
---
description: Audit existing docs against live code, then create a comprehensive GitHub issue in PraisonAIDocs with correct, tested information ready for a writer/agent to implement immediately
---
# Create PraisonAIDocs Issue Workflow
Audit code → Compare with existing docs → Draft correct content → Create issue.
> **When to use this:** A feature is already implemented in PraisonAI but the docs are missing, outdated, or wrong. You need to file a self-contained docs issue in `MervinPraison/PraisonAIDocs` that a writer or agent can act on without asking follow-up questions.
> **When NOT to use this:** Use `@[/create-github-issue]` for new integrations that need external research. Use `@[/local-fix]` if you are writing the docs yourself.
---
## Phase 1 — Identify the Feature & Existing Docs
### 1a. Find the relevant doc file
```bash
ls /Users/praison/PraisonAIDocs/docs/<section>/
cat /Users/praison/PraisonAIDocs/docs/<section>/<feature>.mdx
```
Key doc sections:
- `docs/observability/` — tracing providers (Langfuse, LangSmith, etc.)
- `docs/tools/` — tool integrations
- `docs/features/` — agent features
- `docs/cli/` — CLI commands
- `docs/guides/` — how-to guides
### 1b. Read the existing doc fully
Note every claim that needs verification:
- Install commands
- Import statements
- API method names and signatures
- Environment variable names
- CLI commands
---
## Phase 2 — Audit the Live Code
### 2a. Find the source implementation
```bash
# Search praisonaiagents core SDK
grep -rn "<feature>" /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/ 2>&1 | grep -v ".pyc"
# Search praisonai wrapper (CLI, integrations)
grep -rn "<feature>" /Users/praison/praisonai-package/src/praisonai/praisonai/ 2>&1 | grep -v ".pyc"
# Search praisonai-tools
grep -rn "<feature>" /Users/praison/PraisonAI-tools/ 2>&1 | grep -v ".pyc"
```
### 2b. Read all relevant source files end-to-end
Read every file that implements the feature. For each file capture:
- Actual class/function names and signatures
- Required vs optional parameters
- Environment variables read (exact names)
- What gets called internally (trace the call chain)
- Any version-specific behavior
Key files to always check:
| File pattern | What to look for |
|---|---|
| `praisonaiagents/obs/__init__.py` | `_LazyObsModule`, factory methods, `auto()` |
| `praisonai_tools/observability/providers/<name>_provider.py` | `init()`, `is_available()`, `shutdown()`, `flush()` |
| `praisonai/observability/<name>.py` | CLI sink adapter, event handling |
| `praisonai/cli/commands/<name>.py` | All CLI sub-commands and options |
| `praisonai/__init__.py` | Global env var overrides that may interfere |
### 2c. Test the feature live
Run minimal test scripts to verify the actual behavior:
```bash
# Test the import works
python3 -c "from praisonaiagents.obs import obs; provider = obs.<name>(); print(type(provider).__name__, provider._initialized)"
# Test CLI commands
praisonai <feature> --help
praisonai <feature> <subcommand>
# Verify traces/output appear
timeout 30 praisonai <feature> <subcommand> --limit 5
```
### 2d. Build a "What's Wrong" table
For each doc claim that is incorrect, record:
| Current Doc (Wrong) | Correct |
|---|---|
| wrong install command | correct install |
| wrong import | correct import |
| non-existent method | actual method |
| wrong env var name | actual env var |
---
## Phase 3 — Draft the Issue
The issue body must be **self-contained and implementation-ready**. A writer should be able to update the doc by reading only the issue — no follow-up questions.
### Required sections:
```markdown
## Overview
One paragraph: what doc file needs updating, why it's wrong, and the end goal.
State explicitly: "All code in this issue has been tested and verified working."
## What's Wrong With the Current Docs
Table: Current (Wrong) | Correct
Cover: install commands, imports, API methods, env vars, missing sections.
## Correct Architecture (How It Actually Works)
Explain the actual internal call chain so the writer understands context.
Include a text diagram if helpful.
## Required Install
Exact pip commands, nothing more.
## Environment Variables
Table: Variable | Required | Description
Show bash export examples for both cloud and self-hosted.
## Python Usage
### Quickstart (Recommended)
Full working code with correct imports, init, agent run, and flush.
### Auto-Detection
Document obs.auto() or equivalent if applicable.
### Additional Patterns
Any other valid usage patterns (explicit provider, multi-agent, etc.).
## CLI Usage (if applicable)
All sub-commands with flags and examples.
Include an end-to-end CLI session example.
## Configuration File (if applicable)
Document any config files that are auto-created or auto-read.
## What Output Looks Like
Show what traces/output actually look like after a successful run.
## Version Compatibility Notes
Document any breaking changes between SDK versions that affect usage.
## Files to Update
Table: File | Change
## Acceptance Criteria
- [ ] Checkbox list — each item must be specific and verifiable
## References
List all source files read (with absolute paths).
```
---
## Phase 4 — Create the Issue
### 4a. Write body to a temp file
```bash
cat > /tmp/docs_issue_<feature>.md << 'EOF'
<issue body>
EOF
```
### 4b. Create via `gh` CLI
```bash
gh issue create \
--repo MervinPraison/PraisonAIDocs \
--title "Docs: <action verb> <feature> page — <one-line summary of what's wrong>" \
--label "documentation" \
--body-file /tmp/docs_issue_<feature>.md
```
**Title format:** `Docs: Rewrite/Update/Add <Feature> page — <what's wrong or missing>`
Examples:
- `Docs: Rewrite Langfuse integration page with correct Langfuse v4 API and CLI commands`
- `Docs: Add obs.auto() documentation to observability overview`
- `Docs: Fix LangSmith install command and update import paths`
### 4c. Verify
```bash
gh issue view <number> --repo MervinPraison/PraisonAIDocs | head -30
```
Confirm the URL: `https://github.com/MervinPraison/PraisonAIDocs/issues/<number>`
---
## Checklist — Before Creating the Issue
- [ ] Existing doc file read completely
- [ ] All source files implementing the feature read end-to-end (not skimmed)
- [ ] Feature tested live — not just code-read
- [ ] "What's Wrong" table is complete and specific
- [ ] All code examples in the issue are copy-pastable and tested
- [ ] All env var names are verified against source (not guessed)
- [ ] All CLI commands verified with `--help` and live run
- [ ] Acceptance criteria are specific and verifiable (not vague)
- [ ] References list includes all source file paths read
- [ ] Issue is self-contained — writer needs no follow-up
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---|---|
| Documenting what the code *should* do, not what it *does* | Run it. Test it. Document the actual behavior. |
| Copying import paths from docs being replaced | Always verify imports against source files |
| Missing the "What's Wrong" table | This is the most important section — be explicit |
| Vague acceptance criteria like "docs are updated" | Write specific, testable criteria: "install command is `pip install langfuse`" |
| Not checking for interfering globals (e.g. `OTEL_SDK_DISABLED`) | Always grep `__init__.py` files for env var overrides |
| Forgetting `provider.flush()` in examples | Async buffers need explicit flush before process exit |
| Not testing with a real API key | Code-reading alone misses runtime errors |
| Using `timeout` too short for first-run (downloads, auth) | Use `timeout 120` for agent runs, `timeout 30` for CLI |
+308
View File
@@ -0,0 +1,308 @@
---
description: Research a topic in-depth, analyze both external and local codebases, and create a comprehensive GitHub issue — ready for another agent/developer to act on immediately
---
# Create GitHub Issue Workflow
Research → Clone & Analyze → PraisonAI Analysis → Draft → Create Issue.
> **When to use this:** You need to create a detailed, implementation-ready GitHub issue for a new integration, feature, or benchmark. The issue must contain enough context that another agent or developer can implement it without asking further questions.
> **When NOT to use this:** Use `@[/local-fix]` if you are implementing the change yourself, not just filing an issue.
---
## Phase 1 — Online Research
### 1a. Read official sources
Research the topic from all primary sources: official site, GitHub repo, documentation, blog posts.
```bash
# Example searches (adapt to your topic)
# - Official site / announcement pages
# - GitHub README and docs
# - Third-party write-ups (e.g. Snorkel AI, Epoch AI)
# - Framework documentation (core concepts, agents, running)
```
URLs to read for each source (use `read_url_content` tool):
- Official announcement / news page
- GitHub repository README (multiple chunks if large)
- Framework/integration documentation pages
- Any relevant blog posts or analysis
**Capture for the issue:**
- What is it? Purpose and design goals
- Key terminology and concepts (with definitions)
- Architecture overview
- Current leaderboard / ecosystem state
- References list (all URLs)
### 1b. Read paginated content
For large pages, read additional chunks:
```
view_content_chunk(document_id=<url>, position=2)
view_content_chunk(document_id=<url>, position=3)
view_content_chunk(document_id=<url>, position=4)
```
Continue until all relevant sections are read (core concepts, agent types, running instructions, integration API).
---
## Phase 2 — Clone & Analyze External Codebase
### 2a. Clone the repository
```bash
git clone <repo-url> ~/<repo-name> --depth=1
```
### 2b. Explore structure
```bash
ls -la ~/<repo-name>/
ls -la ~/<repo-name>/src/
```
Key files to read (adapt paths to repo):
- `AGENTS.md` / `CLAUDE.md` / `README.md` — architecture overview
- Base class files (e.g. `base.py` for agents, environments)
- Factory / registry files (how things are registered)
- Model/config files (data structures agents must populate)
- Enum files (valid names, types)
- Example agent implementations (minimal + full-featured)
- `pyproject.toml` — Python version, dependencies
**Capture for the issue:**
- Repository structure diagram
- Key file paths with line counts
- Base class interface (all abstract methods with signatures)
- How to register a new agent (enum + factory pattern)
- Data models the agent must populate (`AgentContext`, etc.)
- Example agent implementations (minimal and production)
- CLI commands to run the integration
- Environment variables required
### 2c. Read base classes end-to-end
Read every relevant base class completely. For agent integrations:
```
read_file(base.py) # BaseAgent / BaseInstalledAgent
read_file(factory.py) # AgentFactory registration
read_file(models/agent/name.py) # AgentName enum
read_file(models/agent/context.py) # AgentContext fields
read_file(examples/agents/minimal_agent.py) # Minimal example
read_file(agents/installed/reference_agent.py) # Full example
```
### 2d. Read a reference implementation
Pick the most complete existing agent implementation (e.g. `codex.py`, `gemini_cli.py`) and read it fully. This reveals:
- Install pattern (system packages → user packages)
- Version detection (`get_version_command` / `parse_version`)
- `@with_prompt_template` decorator usage
- `populate_context_post_run` for token tracking
- ATIF trajectory support (`SUPPORTS_ATIF`)
- `CliFlag` / `EnvVar` declarative config
- `exec_as_root` vs `exec_as_agent` usage
---
## Phase 3 — Analyze PraisonAI Codebase
### 3a. Identify relevant components
```bash
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/tools/
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/agent/
```
Key files to read for agent integration issues:
| File | What to look for |
|------|-----------------|
| `praisonaiagents/tools/shell_tools.py` | `execute_command`, approval decorators |
| `praisonaiagents/agent/agent.py` | `Agent.start()`, `Agent.chat()`, token tracking |
| `praisonaiagents/approval/` | `@require_approval`, auto-approval backend |
| `praisonaiagents/eval/` | Evaluation framework hooks |
| `praisonaiagents/agents/agents.py` | `AgentTeam` multi-agent |
| `pyproject.toml` | Current version, optional dependencies |
### 3b. Map integration points
For each PraisonAI component, document:
- What it does
- How it maps to the external system's interface
- What needs bridging (e.g. wrapping `environment.exec()` as a tool)
- Known gotchas (e.g. `@require_approval` must be bypassed in containers)
---
## Phase 4 — Draft the Issue
The issue body must be self-contained. Another agent must be able to implement the feature by reading only the issue — no follow-up questions.
### Required sections:
```markdown
## Overview
One paragraph: what, why, and the end goal.
## Background: What is <X>?
- Purpose and design goals
- Key statistics (task count, solve rates, etc.)
- Why <X> + PraisonAI is valuable
- Current ecosystem / leaderboard state
## <X> Architecture (Codebase Analysis)
> Repo analyzed locally: `~/<repo-name>` (cloned at `~/<repo-name>`)
### Core Concepts
Table: Concept | Description
### Two (or N) Integration Types
Code examples for each type with full signatures.
### Key File Locations in <X> Codebase
Directory tree with annotations for each important file.
### Data Models
Full class definitions the agent must populate.
### How to Run (CLI)
All relevant CLI commands with flags and examples.
## PraisonAI Architecture (Relevant to This Integration)
Table: Component | Location | Relevance
### PraisonAI Execution Model
How PraisonAI currently handles the relevant operations, and what must be adapted.
## Proposed Implementation Plan
### Approach: <Recommended> (with justification)
### Phase 1: Minimal Proof-of-Concept
Full working code example.
### Phase 2: Production Implementation
Full working code example.
### Phase N: Advanced Features
(ATIF, multi-agent, etc.)
## Files to Create / Modify
### New files (praisonai-package)
Table: File | Purpose
### Modifications to <External Repo> (PR upstream)
Table: File | Change
## Technical Considerations
Subsections for:
- Container/environment dependencies
- API key forwarding
- Safety/approval bypass
- Token tracking
- Parallel execution safety
## Job / Config Example
Working YAML config + CLI invocation.
## Use Cases Unlocked
Table: Use Case | How
## Acceptance Criteria
- [ ] Checkbox list of verifiable outcomes
## Implementation Notes for the Assigned Agent/Developer
### Key <X> Files to Read First
Numbered list with file paths and line counts.
### Key PraisonAI Files to Read
Numbered list with file paths.
### Critical Integration Points
Numbered list of the exact code-level bridges needed.
### Architecture Decision
Why the chosen approach (installed vs external, etc.) with trade-offs.
### Installation & Testing Commands
Copy-pastable commands to install, verify, and run.
### Upstream PR
What to submit upstream and where.
## References
Bullet list of all URLs used.
```
---
## Phase 5 — Create the Issue
### 5a. Create via `gh` CLI
```bash
gh issue create \
--repo <org>/<repo> \
--title "Feature: <Descriptive Title>" \
--label "enhancement" \
--body "<issue body>"
```
**Title format:** `Feature: <What> with <Integration> (<Framework/Version>)`
Example:
```bash
gh issue create \
--repo MervinPraison/PraisonAI \
--title "Feature: Integrate PraisonAI Agents with Terminal-Bench 2.0 (Harbor Framework)" \
--label "enhancement" \
--body "..."
```
### 5b. Verify the issue was created
```bash
gh issue view <issue-number> --repo <org>/<repo> | head -20
```
The output URL confirms success: `https://github.com/<org>/<repo>/issues/<number>`
---
## Checklist — Before Creating the Issue
- [ ] All primary documentation URLs read (including paginated chunks)
- [ ] External repo cloned locally and analyzed
- [ ] Base classes read end-to-end (not just skimmed)
- [ ] At least one reference implementation read fully
- [ ] PraisonAI codebase analyzed for integration points
- [ ] Issue body has working code examples (not pseudocode)
- [ ] All file paths are absolute and verified to exist
- [ ] CLI commands are copy-pastable and complete
- [ ] Acceptance criteria are verifiable (not vague)
- [ ] References section includes all URLs used
- [ ] Issue is self-contained — no "see docs for details" without the details
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---------|-----|
| Pseudocode in examples | Use real, runnable code with imports |
| Vague file paths like `agents/` | Use absolute paths like `~/harbor/src/harbor/agents/base.py` |
| Missing `--depth=1` on clone | Large repos take forever; always use shallow clone |
| Only reading chunk 0 of a URL | Read chunks 1–4+ for paginated content |
| Skipping the factory/registry file | This is where registration happens; always read it |
| Not reading a reference agent | Pattern is not obvious from base class alone |
| Forgetting API key forwarding section | Always document how secrets are passed to containers |
| Skipping `populate_context_post_run` | Harbor uses this for token tracking and leaderboard data |
| Missing upstream PR instructions | Specify exact files to modify upstream for first-class support |
+190
View File
@@ -0,0 +1,190 @@
---
description: create and publish a post on mer.vin using praisonaiwp
---
## Config
- Server: `default` → `https://mer.vin`
- Config: `~/.praisonaiwp/config.yaml`
- Category for PraisonAI features: `PraisonAI`
---
## Step 1 — Compose the content
Structure every post as:
1. **Intro paragraph** — one sentence, what the feature solves
2. **Mermaid diagram** — architecture/flow (see block format below)
3. **Sections** — H2 headings, tables > prose, code blocks for usage
4. **Performance/summary** — table with concrete numbers
Keep it technical. Lead with diagrams and tables, not paragraphs.
---
## Step 2 — Mermaid block format (merpress)
> **Creating merpress:** Install the [Merpress – Mermaid for WordPress](https://wordpress.org/plugins/merpress/) plugin via `wp plugin install merpress --activate --allow-root` on the server. It adds the `wp:merpress/mermaidjs` block used below.
All posts use the native `wp:merpress/mermaidjs` block. Use this exact format:
```
<!-- wp:merpress/mermaidjs {"align":"full"} -->
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid alignfull"><pre class="mermaid">%%{init: {"theme": "base", "themeVariables": {"background": "transparent", "lineColor": "#000000"}}}%%
graph TD
A[Input] --> B[Agent]
B --> C[Tool]
C --> D[Output]
classDef hook fill:#189AB4,color:#fff
classDef agent fill:#8B0000,color:#fff
classDef decision fill:#444,color:#fff
class B agent
class C hook
</pre></div>
<!-- /wp:merpress/mermaidjs -->
```
**Do NOT use:** `[mermaid]...[/mermaid]` shortcode — that is the wrong format.
Color scheme:
- `#8B0000` (dark red) — agents, inputs, outputs
- `#189AB4` (teal) — tools, hooks
- `#444` — decisions/conditionals
---
## Step 2a — SVG/image upload via SSH
`praisonaiwp media upload` correctly SFTPs the file to `/tmp/` on the server, but
`_execute_wp()` in `~/praisonaiwp-cli/praisonaiwp/core/wp_client.py` never appends
`--allow-root`. Use direct SSH instead.
**SVG upload (Safe SVG plugin active on mer.vin):**
```bash
# 1. SCP SVG to server
scp -i ~/.ssh/id_ed25519 /path/to/diagram.svg <SSH_USER>@<SERVER_IP>:/tmp/
# 2. Import via WP-CLI — must pass --user=<admin> so Safe SVG capability check passes
ssh -i ~/.ssh/id_ed25519 <SSH_USER>@<SERVER_IP> \
"cd <WP_ROOT> && \
wp media import /tmp/diagram.svg --post_id=<POST_ID> \
--title='Title' --alt='Alt' --user=praison --allow-root --porcelain"
# → returns media ID
# 3. Get the URL
ssh -i ~/.ssh/id_ed25519 <SSH_USER>@<SERVER_IP> \
"cd <WP_ROOT> && \
wp post get <MEDIA_ID> --field=guid --allow-root"
```
> **Key:** `--user=praison` is required — Safe SVG checks upload capability against the
> current WP user. Without it, even with the plugin active, SVG imports are blocked.
**PNG fallback (if Safe SVG not available):**
```bash
rsvg-convert -w 1360 /path/to/diagram.svg -o /tmp/diagram_2x.png
# Then follow the same SSH steps above using the .png file (no --user needed)
```
Use this Gutenberg image block in the post content:
```
<!-- wp:image {"id":<MEDIA_ID>,"sizeSlug":"full","linkDestination":"none"} -->
<figure class="wp-block-image size-full"><img src="<IMAGE_URL>" alt="Alt text" class="wp-image-<MEDIA_ID>"/></figure>
<!-- /wp:image -->
```
---
## Step 3 — Create the post
```bash
praisonaiwp create "Post Title" \
--status publish \
--content '<FULL GUTENBERG CONTENT>'
```
Note the returned **Post ID** from the output.
---
## Step 4 — Set category
```bash
praisonaiwp update <POST_ID> --category "PraisonAI"
```
---
## Step 5 — Validate mermaid format
```bash
ssh -i ~/.ssh/id_ed25519 <SSH_USER>@<SERVER_IP> \
"cd <WP_ROOT> && \
wp post get <POST_ID> --field=post_content --allow-root | grep -i mermaid"
```
Expected output must contain `wp:merpress/mermaidjs`, not `[mermaid]`.
---
## Key Gutenberg blocks reference
```
<!-- wp:paragraph --><p>text</p><!-- /wp:paragraph -->
<!-- wp:heading --><h2 class="wp-block-heading">Title</h2><!-- /wp:heading -->
<!-- wp:heading {"level":3} --><h3 class="wp-block-heading">Sub</h3><!-- /wp:heading -->
<!-- wp:code --><pre class="wp-block-code"><code>code here</code></pre><!-- /wp:code -->
<!-- wp:table -->
<figure class="wp-block-table"><table>
<thead><tr><th>Col</th></tr></thead>
<tbody><tr><td>Val</td></tr></tbody>
</table></figure>
<!-- /wp:table -->
<!-- wp:list --><ul class="wp-block-list"><li>item</li></ul><!-- /wp:list -->
<!-- wp:separator --><hr class="wp-block-separator has-alpha-channel-opacity"/><!-- /wp:separator -->
```
---
## Full example command
```bash
praisonaiwp create "Feature Name: What It Does" \
--status publish \
--content '<!-- wp:paragraph -->
<p>One sentence intro.</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">Architecture</h2>
<!-- /wp:heading -->
<!-- wp:merpress/mermaidjs {"align":"full"} -->
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid alignfull"><pre class="mermaid">%%{init: {"theme": "base", "themeVariables": {"background": "transparent", "lineColor": "#000000"}}}%%
graph TD
A[Start] --> B[Agent]
class B agent
classDef agent fill:#8B0000,color:#fff
</pre></div>
<!-- /wp:merpress/mermaidjs -->
<!-- wp:code -->
<pre class="wp-block-code"><code>from praisonaiagents import Agent
agent = Agent(name="example")
result = agent.start("task")</code></pre>
<!-- /wp:code -->'
# Then set category:
praisonaiwp update <ID> --category "PraisonAI"
```
@@ -0,0 +1,670 @@
---
description: End-to-end workflow — deep analysis → GitHub issue → wait for implementing agents → create PR if missing → wait for reviewing agents → review PR locally → feedback to @claude → merge to main when robust per AGENTS.md
---
# End-to-End: Analysis → Issue → PR → Review → Merge
Deep Analysis → Gap Analysis → Critical Review → Plan → Create Issue → **Wait for implementing agents** → **Create PR if missing** → **Wait for reviewers** → **Validate PR locally** → **Feedback to @claude** → **Re-review after fixes** → **Merge to main if robust**.
> **When to use this:** You want a fully hands-off delivery loop. You describe a feature/integration/fix; this workflow produces the issue, monitors implementation by other agents (Claude, Copilot, CodeRabbit), validates their PR locally against `AGENTS.md` principles, loops feedback until the PR is robust, and merges to `main`.
> **When NOT to use this:** Use `/analysis-github-issue-create` if you only want the issue (no PR/merge). Use `/local-fix` if you are the implementer.
---
## PRINCIPLES (apply throughout)
- **Agent-centric**: Agents, workflows, sessions, tools, memory, multi-agent safety.
- **Protocol-driven core**: `praisonaiagents` = lightweight, protocol-first (protocols/hooks/adapters only).
- **DRY**: identify reuse; avoid duplication.
- **No perf impact**: preserve import-time and hot-path; heavy deps optional + lazy.
- **Async-safe + multi-agent safe** by default.
- **Easy for non-developers**: "Few lines of code to do the task!"
- **No competitor names in public surfaces**: Never mention competitor product, company, or project names in GitHub issues, PRs, commit messages, release notes, docs, or any other public-facing content. Refer to capabilities generically (e.g., "self-improving agent pattern", "external agent framework").
- **Test before merge**: never merge unvalidated PRs. Always clone the branch locally and run the tests.
- **Minimal code change**: prefer upstream one-line fixes over downstream workarounds.
---
## CANONICAL PATHS
```
Core SDK: /Users/praison/praisonai-package/src/praisonai-agents (praisonaiagents)
Wrapper: /Users/praison/praisonai-package/src/praisonai (praisonai)
Tools: /Users/praison/PraisonAI-tools
Docs: /Users/praison/PraisonAIDocs
TypeScript: /Users/praison/praisonai-package/src/praisonai-ts
AGENTS.md: /Users/praison/praisonai-package/src/praisonai-agents/AGENTS.md
```
---
# PART A — ANALYSIS & ISSUE (Phases 1–9)
These phases are identical to `/analysis-github-issue-create`. Execute them in order. **Do not implement any code** in these phases — they produce analysis and an issue only.
## Phase 1 — Acceptance Criteria
Translate the request into testable criteria:
- API expectations (classes, methods, signatures)
- CLI expectations (commands, flags, help text)
- Documentation expectations (pages, examples)
- Test expectations (unit, integration, smoke, real agentic)
- Performance constraints (import time, hot-path)
---
## Phase 2 — External Research (if applicable)
### 2a. Read official sources
If analyzing an external integration, research from primary sources:
```bash
# Use read_url_content tool for:
# - Official site / announcement pages
# - GitHub README and docs
# - Framework documentation
# - Third-party write-ups
```
**Capture:**
- What is it? Purpose and design goals
- Key terminology and concepts
- Architecture overview
- Current ecosystem state
- References list (all URLs)
### 2b. Clone & analyze external codebase (if applicable)
```bash
git clone <repo-url> ~/<repo-name> --depth=1
ls -la ~/<repo-name>/
```
Key files to read:
- `AGENTS.md` / `README.md` — architecture overview
- Base class files (abstract methods, signatures)
- Factory / registry files (registration pattern)
- Model/config files (data structures)
- Example implementations (minimal + full-featured)
- `pyproject.toml` / `package.json` — dependencies
---
## Phase 3 — PraisonAI Codebase Inventory
### 3a. Inventory with evidence
Go through ALL relevant files, understand current logic end-to-end.
```bash
# Core SDK
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/
grep -r "class.*Protocol" praisonaiagents/ --include="*.py" | wc -l
# Wrapper
ls /Users/praison/praisonai-package/src/praisonai/praisonai/
ls /Users/praison/praisonai-package/src/praisonai/praisonai/cli/commands/
# TypeScript
ls /Users/praison/praisonai-package/src/praisonai-ts/src/
```
**Document:**
- Public APIs: modules/classes/functions and exports
- Protocols/adapters/hooks and extension points
- CLI commands, options, help text
- Integrations (db/observability/tools)
- Tests (unit/integration), fixtures, CI config
- Docs (Mintlify), examples, recipes
Provide: **file paths + key symbols + grep counts + entry points**.
### 3b. Identify DRY opportunities
- Existing abstractions that can be reused
- Duplicated code that should be consolidated
- Existing protocols before creating new ones
---
## Phase 4 — Detailed Analysis
### 4a. Architecture and behavior
- Control flow and data flow
- Concurrency model (sync/async)
- Multi-agent interactions
- Dependency boundaries (core/wrapper/tools)
- Failure modes and error handling
### 4b. Invariants check
Verify these are preserved:
- [ ] Protocol-driven core (no heavy impls in `praisonaiagents`)
- [ ] Lazy imports (optional deps never at module level)
- [ ] Backward compatible (public API changes need deprecation)
- [ ] Safe defaults (new features opt-in)
---
## Phase 5 — Gap Analysis
Compare acceptance criteria vs current state.
### Checklist
| Area | Current State | Gap | Severity | Impact | Placement |
|------|---------------|-----|----------|--------|-----------|
| Core SDK | | | | | |
| Wrapper | | | | | |
| Tools/plugins | | | | | |
| CLI | | | | | |
| Docs | | | | | |
| Tests | | | | | |
| Exports | | | | | |
| Perf | | | | | |
| Multi-agent + async | | | | | |
### Gap severity levels
- **Critical**: Blocks functionality
- **High**: Significant limitation
- **Medium**: Missing feature
- **Low**: Nice-to-have
---
## Phase 6 — Critical Review
### 6a. Risks and footguns
- API ambiguity or edge cases
- Backward compatibility concerns
- Coupling violations
- Performance regressions
- Concurrency hazards
- Misuse risks
- Operational concerns
### 6b. Mitigation strategies
For each risk, document:
- "Safe by default" recommendation
- Explicit opt-in for dangerous behavior
- Documentation warnings
---
## Phase 7 — Implementation Plan
Step-by-step plan (DO NOT implement):
### 7a. Test-first (TDD)
1. Unit tests for new functionality
2. Integration tests for cross-component behavior
3. Smoke tests for quick validation
4. **Real agentic tests** (REQUIRED):
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are helpful")
result = agent.start("Say hello in one sentence")
print(result) # Must call LLM and produce response
```
### 7b. Implementation order
1. Tests (TDD)
2. Core implementation
3. CLI integration
4. Documentation
5. Verification
### 7c. Files to change/create
| File | Action | Purpose |
|------|--------|---------|
| | | |
### 7d. Verification commands
```bash
# Unit tests
pytest tests/unit/test_<feature>.py -v
# Integration tests
pytest tests/integration/test_<feature>.py -v
# Smoke test
python -c "from praisonaiagents import <Feature>; print('OK')"
# Real agentic test
python examples/<feature>_example.py
```
---
## Phase 8 — Draft GitHub Issue
The issue must be **self-contained**. Another agent must be able to implement by reading only the issue.
### Required sections
```markdown
## Overview
One paragraph: what, why, and the end goal.
## Background
- Purpose and design goals
- Why this is valuable
- Current state / ecosystem
## Architecture Analysis
### Current Implementation
- Key files and their purposes
- Integration points
- Data flow
### Key File Locations
| File | Purpose | Lines |
|------|---------|-------|
## Gap Analysis Summary
### Critical Gaps
| Gap | Impact | Effort |
|-----|--------|--------|
### Feature Gaps
| Feature | Current Support | Gap |
|---------|-----------------|-----|
## Proposed Implementation
### Phase 1: Minimal
Working code example.
### Phase 2: Production
Working code example.
## Files to Create / Modify
### New files
| File | Purpose |
|------|---------|
### Modified files
| File | Change |
|------|--------|
## Technical Considerations
- Dependencies
- Performance impact
- Safety / approval
- Multi-agent safety
## Acceptance Criteria
- [ ] Verifiable checkbox list
## Implementation Notes
### Key Files to Read First
1. `path/to/file.py` (N lines) — purpose
### Critical Integration Points
1. Where X connects to Y
### Testing Commands
```bash
# Copy-pastable commands
```
## References
- [Link](url)
```
---
## Phase 9 — Create GitHub Issue
### 9a. Create via `gh` CLI
```bash
gh issue create \
--repo MervinPraison/PraisonAI \
--title "<Type>: <Descriptive Title>" \
--body-file /tmp/issue-body.md
```
**Title formats:**
- `Feature: <What>` — new functionality
- `Integration: <External System>` — external integration
- `Fix: <Problem>` — bug fix proposal
### 9b. Record the issue number
```bash
ISSUE_NUM=$(gh issue view <number> --repo MervinPraison/PraisonAI --json number --jq '.number')
echo "Tracking issue #$ISSUE_NUM"
```
---
# PART B — IMPLEMENTATION MONITORING (Phases 10–15)
After the issue is filed, other agents (`@claude`, GitHub Copilot agent, CodeRabbit) pick it up automatically. This part watches, shepherds, validates, and merges.
## Phase 10 — Wait ~10 min for implementing agents
After `gh issue create`, Claude and Copilot typically start work within seconds and finish a first pass in 5–15 minutes.
```bash
echo "Waiting 10 minutes for implementing agents..."
echo "Start: $(date)"
sleep 600
echo "End: $(date)"
```
### Then check: did they open a PR?
```bash
REPO=MervinPraison/PraisonAI
ISSUE_NUM=<number>
# Check for PRs that reference the issue
gh pr list --repo $REPO --state open --search "fixes #$ISSUE_NUM OR closes #$ISSUE_NUM" --json number,title,headRefName
# Also check for branches matching claude/issue-<N>-* naming convention
gh api repos/$REPO/branches --paginate --jq ".[] | select(.name | startswith(\"claude/issue-$ISSUE_NUM\")) | .name"
```
---
## Phase 11 — Create PR if none exists
If Claude pushed a branch but did not open a PR, open one yourself.
```bash
REPO=MervinPraison/PraisonAI
ISSUE_NUM=<number>
BRANCH=$(gh api repos/$REPO/branches --paginate --jq ".[] | select(.name | startswith(\"claude/issue-$ISSUE_NUM\")) | .name" | head -1)
if [ -n "$BRANCH" ]; then
TITLE=$(gh api repos/$REPO/commits/$BRANCH --jq '.commit.message' | head -1)
gh pr create --repo $REPO --head "$BRANCH" --base main \
--title "$TITLE" \
--body "Automated PR from Claude's work on issue #$ISSUE_NUM.
Branch: \`$BRANCH\`
Closes #$ISSUE_NUM"
fi
```
### If no branch exists after 10 minutes
Re-trigger Claude by commenting on the issue, then wait another 10 minutes and re-check:
```bash
gh issue comment $ISSUE_NUM --repo $REPO \
--body "@claude please pick up this issue — full analysis and plan are in the issue body."
sleep 600
```
---
## Phase 12 — Wait ~10 min for reviewing agents
Once a PR exists, `CodeRabbit`, `Copilot`, and CI pipelines run. Give them time to complete.
```bash
echo "Waiting 10 minutes for PR reviewers and CI..."
sleep 600
```
### Collect status
```bash
PR=<pr-number>
gh pr view $PR --repo $REPO --json state,mergeable,mergeStateStatus,updatedAt,commits,files \
| python -c "
import json,sys
d=json.load(sys.stdin)
print(f\" State: {d['state']} Mergeable: {d['mergeable']} MergeState: {d['mergeStateStatus']}\")
print(f\" Commits: {len(d['commits'])}\")
for f in d['files']:
print(f\" {f['path']}: +{f['additions']} -{f['deletions']}\")
"
# CI & review checks
gh pr view $PR --repo $REPO --json statusCheckRollup > /tmp/pr-checks.json
python -c "
import json
for c in json.load(open('/tmp/pr-checks.json'))['statusCheckRollup']:
s = c.get('conclusion') or c.get('status','?')
name = c.get('name') or c.get('context','?')
if s and s not in ('SKIPPED',):
print(f' {name}: {s}')
"
```
---
## Phase 13 — Validate the PR locally
**Never merge an unvalidated PR.** Always clone the branch and run tests.
```bash
REPO_URL=https://github.com/MervinPraison/PraisonAI.git
BRANCH=<branch-name>
WORKDIR=/tmp/pr-validate
rm -rf $WORKDIR
git clone --depth 1 --branch "$BRANCH" $REPO_URL $WORKDIR
cd $WORKDIR
# Files touched by the PR
gh pr view $PR --repo $REPO --json files --jq '.files[].path'
# Run the tests for changed files — ALWAYS use timeout (user global rule)
timeout 120 python -m pytest <test-paths> -v --tb=short
# Critical invariant checks (adapt per feature):
# 1) Lazy-import: heavy deps never imported at module level
timeout 30 python - <<'PY'
import sys
from praisonai.observability import <NewThing> # example
assert 'heavy_dep' not in sys.modules, "eager import — violates AGENTS.md §4.2"
print("OK: lazy import preserved")
PY
# 2) Cold-import benchmark (no regression)
timeout 30 python -c "import time; t=time.time(); import praisonaiagents; print(f'{(time.time()-t)*1000:.1f} ms')"
```
### Mergeability gate
A PR is **ready to merge only if ALL of these are true**:
- [ ] `gh pr view` reports `mergeable=MERGEABLE` and `mergeStateStatus` in `CLEAN`/`UNSTABLE` (not `DIRTY`/`BLOCKED`).
- [ ] All `test (3.x)` matrix jobs report `SUCCESS`.
- [ ] Local `pytest` on the changed test files passes with **zero failures** (skipped/xfailed tests are OK).
- [ ] Lazy-import invariant preserved (if the feature adds an optional dep).
- [ ] Cold-import time within ±2 % of `main` (AGENTS.md §4.2).
- [ ] No files outside the issue's declared scope were changed.
- [ ] The diff respects all invariants in AGENTS.md §4.6.
If **any** is false → go to Phase 14 (feedback). Do not merge.
---
## Phase 14 — Feedback to `@claude` when issues found
When validation fails, post a precise, actionable comment tagging `@claude`, referencing the exact test name, error, file, and the AGENTS.md principle violated.
```bash
gh pr comment $PR --repo $REPO --body "$(cat <<'EOF'
Hold on merge: validated locally on HEAD `<short-sha>` and found these issues:
**Test failures:**
```
FAILED tests/.../test_x.py::TestY::test_z
AssertionError: <actual-message>
```
**Root cause:** <one-line diagnosis referencing the exact file and line>.
**AGENTS.md violation(s):**
- §<section>: <principle>
**Requested fix (minimal):**
- Change `<file>:<line>` to `<what>`.
- Or update the test assertion to `<what>` (if the test is wrong, not the code).
**What already passes:**
- N/M tests pass.
- Lazy-import invariant preserved ✅ (or not — state explicitly).
@claude please push a fix. Follow AGENTS.md principles: minimal change, protocol-driven, no perf impact, lazy imports, backward-compatible, safe defaults. Make sure the PR is robust — run the tests locally before force-pushing.
EOF
)"
```
### Loop
After commenting:
```bash
echo "Waiting 10 minutes for Claude to push fixes..."
sleep 600
# → return to Phase 12 (fetch new commits, re-run checks)
```
Repeat Phases 12 → 13 → 14 until the mergeability gate in Phase 13 is fully green, or escalate to a human after 3 failed rounds.
### When the PR has merge conflicts
If `mergeStateStatus=DIRTY`, ask Claude to rebase rather than resolving conflicts yourself on non-trivial logic:
```bash
gh pr comment $PR --repo $REPO --body "@claude this PR has merge conflicts with \`main\` (PR #<X> was merged, touching the same regions). Please rebase onto latest \`main\`, re-run \`pytest <paths>\`, and force-push."
```
---
## Phase 15 — Merge to `main`
Once Phase 13's gate is fully green:
### 15a. Final diff review against AGENTS.md
```bash
gh pr diff $PR --repo $REPO | less
```
**Hard gate — every box must be ticked before merge:**
- [ ] **Protocol-driven core (§4.1)**: no heavy implementations leaked into `praisonaiagents`.
- [ ] **No perf impact (§4.2)**: lazy imports confirmed; import benchmark within ±2 %.
- [ ] **DRY (§4.3)**: no new duplication; existing protocols/adapters reused where possible.
- [ ] **Agent-centric (§4.4)**: API centers on agents/sessions/tools/memory.
- [ ] **Async-safe + multi-agent safe (§4.5)**: no shared mutable globals; locks where needed.
- [ ] **Invariants preserved (§4.6)**: backward compatible, safe defaults, deterministic tests.
- [ ] **Naming conventions (§4.9)**: `XProtocol` for interfaces, `XAdapter` for impls, `add_*`/`get_*`/`save`/`load` verbs.
- [ ] No `.md` files added beyond those explicitly requested (per user global rule).
- [ ] Tests run locally with `timeout` — never hang (per user global rule).
### 15b. Merge
```bash
gh pr merge $PR --repo $REPO --squash --delete-branch
# --squash preserves linear main; --delete-branch keeps the repo clean
```
### 15c. Verify
```bash
gh pr view $PR --repo $REPO --json state,mergedAt,mergeCommit
gh issue view $ISSUE_NUM --repo $REPO --json state # should auto-close
```
---
# Orchestration Snippet (one-shot reference)
For a single end-to-end invocation, chain Part B phases:
```bash
#!/usr/bin/env bash
set -euo pipefail
REPO=MervinPraison/PraisonAI
ISSUE_NUM=<fill>
# Phase 10: wait for implementing agents
sleep 600
# Phase 11: ensure PR exists
BRANCH=$(gh api repos/$REPO/branches --paginate \
--jq ".[] | select(.name | startswith(\"claude/issue-$ISSUE_NUM\")) | .name" | head -1)
PR=$(gh pr list --repo $REPO --state open --head "$BRANCH" --json number --jq '.[0].number' 2>/dev/null || true)
if [ -z "$PR" ] && [ -n "$BRANCH" ]; then
TITLE=$(gh api repos/$REPO/commits/$BRANCH --jq '.commit.message' | head -1)
gh pr create --repo $REPO --head "$BRANCH" --base main \
--title "$TITLE" --body "Closes #$ISSUE_NUM"
PR=$(gh pr list --repo $REPO --state open --head "$BRANCH" --json number --jq '.[0].number')
fi
echo "Tracking PR #$PR"
# Phase 12: wait for reviewers + CI
sleep 600
# Phases 13–14: validate + feedback loop (cap at 3 rounds)
for round in 1 2 3; do
echo "=== Validation round $round ==="
# clone + pytest (per feature) — if green break; else gh pr comment + sleep 600
break # placeholder
done
# Phase 15: merge
gh pr merge $PR --repo $REPO --squash --delete-branch
gh issue view $ISSUE_NUM --repo $REPO --json state
```
---
## Checklist — Before Merging
- [ ] Issue exists and describes the work
- [ ] PR exists and references the issue (`Closes #N`)
- [ ] Branch was fetched and tests were run **locally** — not just CI-trusted
- [ ] All PR-relevant tests pass with zero failures
- [ ] CI matrix (3.10 / 3.11 / 3.12) is all green
- [ ] Lazy-import / cold-import invariants verified if optional deps added
- [ ] Diff reviewed against every AGENTS.md §4 principle
- [ ] `mergeStateStatus` in `CLEAN`/`UNSTABLE`, never `DIRTY`/`BLOCKED`
- [ ] No files outside the issue's scope were changed
- [ ] If feedback was given, `@claude` had a chance to respond and fixed everything
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---------|-----|
| Merging without running tests locally | Always `git clone` the branch and run `pytest` |
| Resolving complex conflicts manually | Ask `@claude` to rebase instead |
| Trusting CI alone | CI jobs can be skipped / out-of-date; local validation is source of truth |
| Vague feedback to `@claude` | Every comment must cite file, line, test name, error, and AGENTS.md section |
| Waiting forever | Cap loops at 3 rounds, then escalate to a human |
| Running commands without `timeout` | Always `timeout 60 ...` per user global rule |
| Creating `.md` docs proactively | Don't — user rule forbids unrequested `.md` files |
| Skipping diff review | Every merge needs a full-diff AGENTS.md pass |
---
## Hard Rules
1. **Never merge without local test validation.**
2. **Never merge when `mergeStateStatus = DIRTY` or `BLOCKED`.**
3. **Every `@claude` comment must be actionable** — file, line, exact fix, AGENTS.md ref.
4. **Cap feedback loops at 3 rounds** — escalate after that, don't spin forever.
5. **Use `--squash --delete-branch`** to keep `main` linear and the repo clean.
6. **Always verify** the issue auto-closed after merge.
7. **All `run_command` calls use `timeout`** to avoid hangs (user global rule).
8. **No proactive `.md` creation** beyond this workflow file (user global rule).
+63
View File
@@ -0,0 +1,63 @@
---
description: Project information and deployment reference for PraisonAIUI
---
## Project: PraisonAIUI
YAML-driven website/docs generator. One YAML file, one docs folder, one command — ship a beautiful documentation site.
**Aim**: AIUI is a standardised, protocol-driven UI framework for building *any* AI-powered interface — not hardcoded to PraisonAI.
## Key Files
| File | Purpose |
|------|---------|
| `aiui.template.yaml` | Site configuration (theme, nav, routes, components) |
| `docs/` | Markdown content directory |
| `src/praisonaiui/` | Python source (CLI, compiler, server, providers) |
| `src/praisonaiui/compiler/` | Build pipeline: config → static site |
| `src/praisonaiui/templates/frontend/` | Bundled React SPA (index.html + assets) |
| `.github/workflows/ci.yml` | CI (lint, test) + GitHub Pages deployment |
| `pyproject.toml` | Package metadata, dependencies, entry points |
| `CNAME` | Custom domain: `ui.praison.ai` |
## CLI Commands
```bash
aiui init # Scaffold new project
aiui build # Compile → static site in ./aiui/
aiui build --output site --minify # For GitHub Pages
aiui serve # Serve built site locally
aiui dev # Dev mode with hot reload
aiui validate # Validate aiui.template.yaml
```
## Build Output
`aiui build` produces a fully static SPA:
- `index.html` + `assets/` — React frontend bundle
- `ui-config.json` — compiled site configuration
- `docs-nav.json` — navigation tree from docs folder
- `route-manifest.json` — route definitions
- `docs/` — copied markdown content
## Deployment
- **CI**: On push to `main`, GitHub Actions runs `aiui build --output site --minify`
- **Deploy**: `peaceiris/actions-gh-pages@v4` pushes `./site/` to `gh-pages` branch
- **Domain**: `ui.praison.ai` via CNAME file copied into build output
- **No server required** — everything is static
## Testing
```bash
pip install -e .[dev]
pytest tests/unit tests/integration -v
ruff check src/praisonaiui
```
## Package
- PyPI name: `aiui`
- Entry points: `aiui` and `praisonaiui` (both map to `praisonaiui.cli:app`)
- Python: ≥3.9
+839
View File
@@ -0,0 +1,839 @@
---
description: Update install.sh and deploy PraisonAI to Kubernetes via Helm (CI/CD Pipeline)
---
# Install.sh Update & Helm Deployment Workflow
Complete guide for updating the PraisonAI install script and deploying to Kubernetes via the full CI/CD pipeline.
**⚠️ CRITICAL**: This workflow contains **NO SECRETS**. All sensitive values (tokens, passwords) must be passed via environment variables or external secret management.
## 📁 Key Locations (MUST KNOW)
### Scripts
| File/Resource | Absolute Path | Purpose |
|---------------|---------------|----------|
| **install.sh** | `/Users/praison/praisonai-package/src/praisonai/scripts/install.sh` | Main bash installer |
| **install.ps1** | `/Users/praison/praisonai-package/src/praisonai/scripts/install.ps1` | PowerShell installer |
### CI/CD Pipeline (GitHub → ACR → Helm → K8s)
| File/Resource | Absolute Path | Purpose |
|---------------|---------------|----------|
| **GitHub Workflow** | `/Users/praison/Sites/localhost/praisonai/.github/workflows/azure-pipeline.yaml` | CI/CD pipeline triggered on git push |
| **Dockerfile.php** | `/Users/praison/Sites/localhost/praisonai/Dockerfile.php` | PHP container build |
| **Dockerfile.nginx** | `/Users/praison/Sites/localhost/praisonai/Dockerfile.nginx` | Nginx container build |
| **Dockerfile.init** | `/Users/praison/Sites/localhost/praisonai/Dockerfile.init` | Init container build |
### Helm Deployment
| File/Resource | Absolute Path | Purpose |
|---------------|---------------|----------|
| **Helm Charts** | `/Users/praison/repos/person/helmcharts/` | All Kubernetes deployments |
| **wb_azure Chart** | `/Users/praison/repos/person/helmcharts/charts/wb_azure/` | PraisonAI WordPress deployment |
| **Production Values** | `/Users/praison/Sites/localhost/praisonai/values-praisonai-production.yaml` | Production Helm config |
| **Local Values** | `/Users/praison/Sites/localhost/praisonai/values-local.yaml` | Local development config |
| **Deployment Docs** | `/Users/praison/Sites/localhost/praisonai/DEPLOYMENT.md` | Deployment documentation |
| **Deployment Makefile** | `/Users/praison/Sites/localhost/praisonai/Makefile` | Deployment automation |
---
## 🔄 Full CI/CD Pipeline Overview
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Git Push │────▶│ GitHub Actions │────▶│ Azure ACR │
│ (master) │ │ azure-pipeline │ │ Image Build │
└─────────────────┘ └──────────────────┘ └────────┬────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Kubernetes │◀────│ Helm Upgrade │◀────│ Update Image │
│ Deployment │ │ (values.yaml) │ │ Tag in Values │
└─────────────────┘ └──────────────────┘ └─────────────────┘
```
### Pipeline Steps:
1. **Git push** to master branch
2. **GitHub Actions** triggers (`.github/workflows/azure-pipeline.yaml`)
3. **Build** Docker images (nginx, php, init)
4. **Push** to Azure Container Registry (ACR)
5. **Update** Helm values with new image tag
6. **Deploy** using Helm upgrade
---
## 🚀 Phase 0 - Fully Automated CI/CD Pipeline
### Complete Auto-Deploy Architecture
```
Git Push ──▶ Build Images ──▶ Trigger Deploy ──▶ Helm Upgrade ──▶ Production
│ │ │ │
│ ▼ ▼ ▼
│ ACR Push helmcharts wb_azure chart
│ (pa-php:SHA) repository (K8s deploy)
│
└─── install.sh ────────────────────────────────────────────────▶ praison.ai/install.sh
```
### Step 0.1: Build Workflow (Automatic on Git Push)
**File**: `/Users/praison/Sites/localhost/praisonai/.github/workflows/azure-pipeline.yaml`
**Repository**: `https://github.com/MervinPraison/praison.ai`
This workflow triggers on every push to `master`:
```yaml
on:
push:
branches: [master]
```
**What it does:**
1. **Syncs install.sh** from PraisonAI repository (only if changed!)
- Checks out `MervinPraison/PraisonAI`
- Compares `install.sh` and `install.ps1` with existing web files
- **Only copies if files have actually changed** (avoids unnecessary redeploys)
- This ensures `https://praison.ai/install.sh` is always latest
2. Downloads env files from Azure Storage
3. Builds multi-arch Docker images (linux/amd64, linux/arm64)
4. Pushes to Azure Container Registry: `praison.azurecr.io/pa/`
5. **Triggers Helm deployment** via `repository_dispatch` event
**Key Step - Automatic Deploy Trigger:**
```yaml
- name: Trigger Helm Deployment
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
curl -X POST \
-H "Authorization: token ${{ secrets.HELM_REPO_TOKEN }}" \
-d '{
"event_type": "deploy_wb_azure",
"client_payload": {
"image_tag": "'"$SHORT_SHA"'",
"source_repo": "'"${{ github.repository }}"'",
"source_commit": "'"${{ github.sha }}"'"
}
}' \
https://api.github.com/repos/praison/helmcharts/dispatches
```
### Step 0.2: Deploy Workflow (Triggered Automatically)
**File**: `/Users/praison/repos/person/helmcharts/.github/workflows/helm-upgrade-with-image.yml`
Listens for `repository_dispatch` events:
```yaml
on:
repository_dispatch:
types: [deploy_wb_azure, deploy_tcs_azure, deploy_tamilmanna_azure]
```
**What it does:**
1. Receives image tag from build workflow
2. Runs `helm upgrade --install wb_azure` with new image tag
3. Waits for rollout to complete
4. Verifies deployment
**Result**: Every git push automatically builds AND deploys!
### Required GitHub Secrets
For the automated CI/CD to work, you need these secrets configured:
**In praisonai site repository** (`https://github.com/MervinPraison/praison.ai`):
| Secret | Purpose |
|--------|---------|
| `AZURE_CREDENTIALS` | Azure login for ACR and AKS |
| `AZURE_USERNAME` | ACR username |
| `AZURE_PASSWORD` | ACR password |
| `AZURE_STORAGE_KEY` | Download env files from Azure Storage |
| `HELM_REPO_TOKEN` | **NEW**: Trigger deploy workflow in helmcharts repo |
**In helmcharts repository** (`/Users/praison/repos/person/helmcharts/.github/workflows/`):
| Secret | Purpose |
|--------|---------|
| `AZURE_CREDENTIALS` | Azure login for AKS |
| `AKS_CLUSTER_NAME` | Kubernetes cluster name |
| `AKS_RESOURCE_GROUP` | Azure resource group |
**To add HELM_REPO_TOKEN**:
1. Go to GitHub Settings → Developer settings → Personal access tokens
2. Create token with `repo` scope
3. Add as secret `HELM_REPO_TOKEN` in https://github.com/MervinPraison/praison.ai
**Current status**: ✅ Already configured (set via `gh secret set`)!
**Images built:**
- `praison.azurecr.io/pa/pa-nginx:SHORT_SHA`
- `praison.azurecr.io/pa/pa-nginx:master`
- `praison.azurecr.io/pa/pa-php:SHORT_SHA`
- `praison.azurecr.io/pa/pa-php:master`
- `praison.azurecr.io/pa/pa-init:SHORT_SHA`
- `praison.azurecr.io/pa/pa-init:master`
### Step 0.2: Update Helm Values with New Image Tag
After the ACR build completes, update the Helm values file to use the new image:
```bash
cd /Users/praison/Sites/localhost/praisonai
# Get the short SHA from the latest commit (matches the Docker tag)
SHORT_SHA=$(git rev-parse --short HEAD)
# Update values file with new image tag
helm upgrade praisonai /Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--set image.tag=$SHORT_SHA \
--namespace default \
--timeout 10m
```
**Alternative**: Update values file permanently:
```bash
# Edit values-praisonai-production.yaml to set image.tag
sed -i "s/tag: \".*\"/tag: \"$SHORT_SHA\"/" values-praisonai-production.yaml
# Then commit and push the updated values
git add values-praisonai-production.yaml
git commit -m "ci: update image tag to $SHORT_SHA"
git push origin master
```
### Step 0.3: Full Automated Script (For CI/CD Integration)
```bash
#!/bin/bash
# deploy-after-build.sh - Run after ACR build completes
set -e
SHORT_SHA=$(git rev-parse --short HEAD)
NAMESPACE=default
RELEASE_NAME=praisonai
CHART_PATH=/Users/praison/repos/person/helmcharts/charts/wb_azure
VALUES_FILE=/Users/praison/Sites/localhost/praisonai/values-praisonai-production.yaml
echo "🚀 Deploying PraisonAI with image tag: $SHORT_SHA"
# Update Helm deployment with new image tag
helm upgrade --install $RELEASE_NAME $CHART_PATH \
-f $VALUES_FILE \
--set image.tag=$SHORT_SHA \
--namespace $NAMESPACE \
--timeout 10m \
--atomic
echo "✅ Deployment complete!"
echo ""
echo "Verify with:"
echo " kubectl get pods -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE_NAME"
echo " helm status $RELEASE_NAME -n $NAMESPACE"
```
---
### Step 0.4: Extend GitHub Actions for Automatic Helm Deployment
To make the CI/CD fully automated (build → deploy), extend the GitHub Actions workflow:
**File to edit**: `/Users/praison/Sites/localhost/praisonai/.github/workflows/azure-pipeline.yaml`
Add a new job after the `build` job:
```yaml
deploy:
needs: build # Wait for build to complete
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: 'v3.13.0'
- name: Get AKS credentials
run: |
az aks get-credentials \
--resource-group your-resource-group \
--name your-aks-cluster-name \
--overwrite-existing
- name: Deploy with Helm
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
helm upgrade --install praisonai \
/Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--set image.tag=$SHORT_SHA \
--namespace default \
--timeout 10m \
--atomic
- name: Verify deployment
run: |
kubectl rollout status deployment/php-nginx -n default
helm status praisonai -n default
```
**Requirements for automatic deploy:**
1. GitHub repository secrets configured:
- `AZURE_CREDENTIALS` - Azure service principal credentials
- `AZURE_STORAGE_KEY` - For downloading env files
- `AZURE_USERNAME` / `AZURE_PASSWORD` - ACR login
2. AKS cluster access configured in Azure
3. Helm and kubectl available in GitHub Actions runner
---
## 🔧 Phase 1 — Update install.sh (Manual, When Needed)
### When to Update
- New PraisonAI version released
- New dependency requirements
- New OS support needed
- Bug fixes in installation process
### Step 1: Read Current install.sh
```bash
# View the install script
cat /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
```
Key sections in install.sh:
- **Lines 1-50**: Header, usage, environment variables documentation
- **Lines 51-150**: OS detection (macOS, Linux, Windows/WSL)
- **Lines 151-300**: Python installation (version checks, package managers)
- **Lines 301-450**: Virtual environment setup
- **Lines 451-550**: PraisonAI package installation
- **Lines 551-637**: PATH configuration, shell integration, verification
### Step 2: Make Changes
**Common Changes:**
#### Update Default Version
```bash
# Find this line (around line 70):
PRAISONAI_VERSION="${PRAISONAI_VERSION:-latest}"
# Change to specific version if needed:
PRAISONAI_VERSION="${PRAISONAI_VERSION:-1.5.0}"
```
#### Add New Environment Variable
```bash
# Add to header section (after line 10, in the comment block):
# PRAISONAI_NEW_FEATURE - Description (default: value)
# Add to actual code (around line 75):
export PRAISONAI_NEW_FEATURE="${PRAISONAI_NEW_FEATURE:-default_value}"
```
#### Update Python Version Requirements
```bash
# Find Python version check (around line 100-120):
PYTHON_MIN_VERSION="3.9"
# Update if needed:
PYTHON_MIN_VERSION="3.10"
```
### Step 3: Test Changes
```bash
# Test locally (dry run)
cd /Users/praison/praisonai-package/src/praisonai/scripts
bash install.sh --dry-run
# Test in Docker (full test)
bash /Users/praison/praisonai-package/src/praisonai/scripts/test-install-smoke.sh
```
### Step 4: Verify Both Scripts
```bash
# Check install.sh syntax
bash -n /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
# Check install.ps1 syntax (if pwsh available)
pwsh -Command "Get-Command /Users/praison/praisonai-package/src/praisonai/scripts/install.ps1"
```
---
## 🚀 Phase 2 — Deploy to Kubernetes (Helm)
### Pre-Deployment Checklist
```bash
# 1. Verify kubectl connection
kubectl get nodes
# 2. Check current Helm releases
helm list -n default
# 3. Verify chart exists
ls /Users/praison/repos/person/helmcharts/charts/wb_azure/
```
### Deployment Types
#### A. Fresh Deployment (First Time)
```bash
cd /Users/praison/Sites/localhost/praisonai
# Option 1: Using Makefile
make deploy
# Option 2: Manual helm command
helm upgrade --install praisonai /Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--namespace default \
--timeout 10m \
--atomic
```
#### B. Update Existing Deployment
```bash
cd /Users/praison/Sites/localhost/praisonai
# Edit values file first
vim values-praisonai-production.yaml
# Then apply
make upgrade
# Or manually:
helm upgrade praisonai /Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--namespace default \
--timeout 10m
```
#### C. Local Development Deployment
```bash
cd /Users/praison/Sites/localhost/praisonai
make local-deploy
```
### Values File Structure
```yaml
# /Users/praison/Sites/localhost/praisonai/values-praisonai-production.yaml
# Core settings
replicaCount: 2
# Database
dbHost: "10.0.0.11"
dbUser: "bible_4"
dbPassword: "changeme" # Override via --set
# OpenAI tokens (for plugin verification)
openaiVerificationToken: "token-here"
# Feature toggles
praisonai:
enabled: true
domain: praison.ai
whiteboard:
enabled: true
domain: whiteboard.gallery
# Disable other sites
bible: { enabled: false }
music: { enabled: false }
save: { enabled: false }
# Resources
resources:
requests:
cpu: 800m
memory: 1024Mi
limits:
cpu: 2000m
memory: 2048Mi
# Auto-scaling
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
# Ingress
ingress:
enabled: true
className: nginx
```
---
## 📊 Phase 3 — Verify Deployment
### Check Deployment Status
```bash
# Using Makefile
make status
# Manual checks
helm status praisonai -n default
kubectl get pods -l app.kubernetes.io/instance=praisonai -n default
kubectl get svc -l app.kubernetes.io/instance=praisonai -n default
```
### Verify All Resources
```bash
# Pods should be Running
kubectl get pods -n default | grep praisonai
# Services should be Active
kubectl get svc -n default | grep praisonai
# Ingress should exist
kubectl get ingress -n default | grep praisonai
# ConfigMaps
kubectl get configmap -n default | grep nginx-config
# Secrets
kubectl get secret -n default | grep db-password
```
### Check Application Health
```bash
# Port forward and test
echo "Visit http://127.0.0.1:8080"
kubectl port-forward svc/php-nginx 8080:80 -n default
# In another terminal:
curl http://127.0.0.1:8080/test.php
```
---
## 🔄 Phase 4 — Rollback (If Needed)
```bash
# View revision history
make history
# Rollback to previous revision
make rollback
# Or manually:
helm rollback praisonai 1 -n default
```
---
## 🛠️ Phase 5 — Troubleshooting
### Problem: "Resource exists and cannot be imported"
**Cause**: Existing Kubernetes resources not managed by Helm.
**Solution**: Adopt resources into Helm
```bash
cd /Users/praison/Sites/localhost/praisonai
./scripts/adopt-resources.sh praisonai default
```
Or manually annotate:
```bash
# For any resource type
kubectl annotate <resource-type> <name> \
meta.helm.sh/release-name=praisonai \
meta.helm.sh/release-namespace=default
kubectl label <resource-type> <name> \
app.kubernetes.io/managed-by=Helm
```
### Problem: Pods Not Starting
```bash
# Check events
kubectl get events -n default --sort-by='.lastTimestamp' | tail -20
# Check pod logs
kubectl logs -l app.kubernetes.io/instance=praisonai -n default
# Describe pod for details
kubectl describe pod <pod-name> -n default
```
### Problem: Image Pull Errors
```bash
# Check image pull secrets
kubectl get secret acr-auth -n default
# Verify ACR auth exists
kubectl create secret docker-registry acr-auth \
--docker-server=praison.azurecr.io \
--docker-username=<username> \
--docker-password=<password> \
-n default
```
---
## 📋 Phase 6 — Post-Deployment
### Update Documentation
If install.sh changed, update:
1. `/Users/praison/PraisonAIDocs/docs/installation.mdx` — Installation docs
2. `/Users/praison/praisonai-package/src/praisonai/scripts/README.md` — Script docs (if exists)
### Verify Website
```bash
# Check praison.ai is accessible
curl -I https://praison.ai
# Check whiteboard.gallery
curl -I https://whiteboard.gallery
```
### Monitor
```bash
# Watch pods
kubectl get pods -l app.kubernetes.io/instance=praisonai -n default -w
# Check resource usage
kubectl top pods -l app.kubernetes.io/instance=praisonai -n default
```
---
## 📚 Reference: Helm Chart Structure
```
/Users/praison/repos/person/helmcharts/charts/wb_azure/
├── Chart.yaml # Chart metadata (name: wb, version: 1.0.1)
├── values.yaml # Default values (fallback)
├── templates/
│ ├── deployment.yaml # Main php-nginx deployment
│ ├── service.yaml # NodePort service
│ ├── ingress.yaml # TLS + routing
│ ├── nginx-configMap.yaml # Server configs
│ ├── db-password-secret.yaml # DB credentials
│ ├── pdb.yaml # Pod disruption budget
│ ├── autoscalar.yml # HPA
│ ├── cert-manager.yaml # TLS certificates
│ └── _helpers.tpl # Template helpers
```
---
## 🎯 Quick Commands Reference
| Task | Command |
|------|---------|
| Deploy | `make deploy` |
| Update | `make upgrade` |
| Status | `make status` |
| History | `make history` |
| Rollback | `make rollback` |
| Logs | `make logs` |
| Restart | `make restart` |
| Local dev | `make local-deploy` |
| Dry run | `make dry-run` |
| Lint | `make lint` |
---
## ⚠️ Critical Rules
1. **Never commit SQL dumps**: `.gitignore` already excludes `*.sql` files
2. **Never commit secrets**: Use `--set` or external secret management
3. **Always test install.sh** after changes (use test-install-smoke.sh)
4. **Always verify deployment** with `make status` after Helm operations
5. **Use Infrastructure as Code**: All changes via Helm values files, never manual kubectl
6. **Version control**: Commit values files (without secrets), never commit generated manifests
---
## 🆘 Getting Help
If stuck:
1. Check `/Users/praison/Sites/localhost/praisonai/DEPLOYMENT.md` for detailed docs
2. Check `/Users/praison/Sites/localhost/praisonai/INFRASTRUCTURE_AS_CODE_SUMMARY.md` for quick reference
3. Run `helm status praisonai -n default` for deployment status
4. Run `kubectl get events -n default` for cluster events
5. View install.sh comments for usage examples (lines 1-50)
---
## 🔄 CI/CD Pipeline Summary (For New Agents)
### Complete Workflow (Fully Automated!)
```
Developer Push ──────────────────────────────────────────────▶ Production
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 1. Git Push to │───▶│ 2. GitHub Actions │───▶│ 3. Sync │
│ master │ │ Trigger │ │ install.sh │
└─────────────────┘ └──────────────────┘ └────────┬─────────┘
│
┌────────────────────────┘
▼
┌──────────────────┐
│ 4. Azure ACR │
│ Build Images │
│ + Push │
└────────┬─────────┘
│
──────▶┌──────────────────┐
│ 5. Trigger Deploy│
│ (repository_ │
│ dispatch) │
└────────┬─────────┘
│
┌─────────────────┐ ┌──────────────────┐ │
│ 7. Production │◀───│ 6. Helm Upgrade │◀──┘
│ Running │ │ Deploy │
│ (includes │ │ │
│ install.sh) │ │ │
└─────────────────┘ └──────────────────┘
```
**🎉 Fully Automated**: Git push → Build → Deploy (No manual steps!)
### Automatic install.sh Sync
**Key Point**: The workflow automatically syncs `install.sh` from `MervinPraison/PraisonAI` repository **only if changed**:
```yaml
- name: Checkout PraisonAI for install.sh
uses: actions/checkout@v2
with:
repository: MervinPraison/PraisonAI
path: praisonai-package
- name: Sync install.sh to web folder (if changed)
run: |
# Only sync if files have actually changed
if ! diff -q praisonai-package/src/praisonai/scripts/install.sh ./web/install.sh; then
cp praisonai-package/src/praisonai/scripts/install.sh ./web/install.sh
fi
```
**Optimization**: Uses `diff` to compare files - only copies when install.sh or install.ps1 have actually changed. This avoids unnecessary Docker layer rebuilds and deployments.
**Result**: `https://praison.ai/install.sh` is automatically updated **only when the source files change**!
### How install.sh is Served
The `web/install.sh` file is copied into the Docker image at `/var/www/html/web/install.sh` and served by nginx:
```nginx
# In nginx-config, requests to praison.ai/install.sh
# are served from /var/www/html/web/install.sh
location / {
root /var/www/html/web;
try_files $uri $uri/ =404;
}
```
**URL Mapping**:
| File in Repo | URL |
|--------------|-----|
| `web/install.sh` | `https://praison.ai/install.sh` |
| `web/install.ps1` | `https://praison.ai/install.ps1` |
### What Files to Edit
| To Change | Edit File |
|-----------|-----------|
| Application code | `/Users/praison/Sites/localhost/praisonai/` (PHP files) |
| Docker images | `Dockerfile.php`, `Dockerfile.nginx`, `Dockerfile.init` |
| CI/CD pipeline | `.github/workflows/azure-pipeline.yaml` |
| Helm deployment config | `values-praisonai-production.yaml` |
| Install script | `/Users/praison/praisonai-package/src/praisonai/scripts/install.sh` |
### Common Tasks
**Task 1: Deploy new code**
```bash
cd /Users/praison/Sites/localhost/praisonai
git add .
git commit -m "feat: new feature"
git push origin master
# CI/CD automatically builds and deploys
```
**Task 2: Update install.sh and deploy**
```bash
# 1. Update install.sh
vim /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
# 2. Test install.sh
bash /Users/praison/praisonai-package/src/praisonai/scripts/install.sh --dry-run
# 3. Commit and push
git add /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
git commit -m "fix: update install script"
git push origin main
# 4. Deploy website (if needed)
cd /Users/praison/Sites/localhost/praisonai
make upgrade
```
**Task 3: Rollback deployment**
```bash
cd /Users/praison/Sites/localhost/praisonai
make rollback
# Or: helm rollback praisonai 1 -n default
```
### Architecture
| Layer | Technology | Purpose |
|-------|------------|---------|
| Source Control | Git/GitHub | Code repository |
| CI/CD | GitHub Actions | Automated build/deploy |
| Container Registry | Azure ACR | Docker image storage |
| Orchestration | Kubernetes (AKS) | Container management |
| Deployment | Helm | K8s package management |
| Ingress | NGINX Ingress + cert-manager | Traffic routing + TLS |
### Security Notes
- **No secrets in workflow files** - All tokens/passwords via env vars
- **ACR authentication** - Uses `acr-auth` secret in Kubernetes
- **GitHub Secrets** - `AZURE_CREDENTIALS`, `AZURE_USERNAME`, `AZURE_PASSWORD`
- **Never commit** `.env` files, SQL dumps, or credentials
+181
View File
@@ -0,0 +1,181 @@
---
description: instruction
---
Create multiple TODOs and sub-TODOs, get all things done.
First: detailed analysis, plan, and gap analysis. Go through all files, understand current logic. Search if needed.
Then: implement, fix, test (TDD, Agent-Centric, no perf impact, DRY). praisonaiagents is protocol-driven. Run unit, integration, smoke, and real agentic tests.
After: re-do detailed analysis/plan to find remaining gaps and propose fixes.
Docs: beginner-friendly, for non-developers. Explain concepts with mermaid diagrams (Dark Red #8B0000 for agents/inputs/outputs, Teal #189AB4 for tools, white #fff text). Less descriptive, more interactive. Use Mintlify components: Accordions, Badge, Callouts (Note/Warning/Info/Tip/Check/Danger), Cards/Columns, CodeGroup, Expandables, Tabs, Steps, Frame, Icon, Tooltip, Mermaid, ParamField, Tables, CardGroup.
You are an expert AI engineer in the PraisonAI ecosystem.
Production-quality code, zero regressions, full verification. Make PraisonAI the best agent framework.
### Core Philosophy
```
Simpler • More extensible • Faster • Agent-centric
```
| Principle | Rule |
|---|---|
| Agent-Centric | Design centers on Agents, workflows, sessions, tools, memory |
| Protocol-Driven | Core SDK: protocols/hooks/adapters only; heavy code in wrapper/tools |
| Minimal API | Fewer params, sensible defaults, explicit overrides |
| Performance-First | Lazy loading, optional deps, no hot-path regressions |
| Production-Ready | Safe by default, multi-agent safe, async-safe |
- Powerful, lightweight, reliable. Easy for non-developers.
- "Few lines of code to do the task!" — SDK and docs must feel this way.
- Each feature runs 3 ways: CLI, YAML, Python.
- Open source, developer-first. Core free, clear upgrade path to paid (support/cloud/services).
- Simple to adopt, hard to misuse, safe by default.
- Prioritise time saved, reduced risk, and operational confidence.
- Reduce production friction, not just add functionality.
- All features must have CLI integration. Agent-first naming and ergonomics.
ENGINEERING PRINCIPLES (MUST)
- DRY: reuse abstractions, no duplication.
- Protocol-driven core: protocols/hooks in core; heavy impl in wrapper/tools.
- No perf impact: lazy imports, optional deps, no global singletons, no heavy module-level work.
- TDD mandatory: tests first.
- Multi-agent + async safe by default.
- AGENTS.md is not for documentation.
CRITICAL REQUIREMENTS
- EXECUTE + VERIFY mode. No guessing. Proof for "done."
- Optional deps only; lazy import everything heavy.
- Every feature/fix: Python + CLI + docs/examples.
- Any core change must be justified: simpler client API, measurable benefit, NO perf regression.
- If TypeScript parity required: update praisonai-ts, but never at cost of Python core performance.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CANONICAL PATHS (MUST use these)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Core SDK: /Users/praison/praisonai-package/src/praisonai-agents → praisonaiagents
- Wrapper: /Users/praison/praisonai-package/src/praisonai → praisonai
- Tools: /Users/praison/PraisonAI-tools → praisonai-tools
- Docs: /Users/praison/PraisonAIDocs (read AGENTS.md first before updating docs)
- Docs JS: /Users/praison/PraisonAIDocs/docs/js | Rust: docs/rust
- Examples: /Users/praison/praisonai-package/examples/
- TypeScript: /Users/praison/praisonai-package/src/praisonai-ts
- Rust: /Users/praison/praisonai-package/src/praisonai-rust (follow praisonai-ts/AGENTS.md)
- UI (this repo): /Users/praison/praisonaiui → praisonaiui
- Extension points: tools/base.py, tools/decorator.py, db/*
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ARCHITECTURE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Core (praisonaiagents): protocol-driven, lightweight. No heavy imports. Only protocols/hooks/adapters.
Wrapper (praisonai): real integrations (DBs, observability, CLI). Lazy imports, optional deps.
Tools (PraisonAI-tools): pluggable, never overload core/wrapper.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MANDATORY EXECUTION FLOW
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PHASE 1 — ANALYSIS (before writing code)
1.1 Acceptance Criteria — testable bullets for API, CLI, docs, tests, perf.
1.2 Repo Inventory — scan relevant files end-to-end:
- modules/classes/APIs/exports, CLI commands, tests, docs/examples
- Evidence: paths + symbols + grep counts. Identify DRY opportunities.
1.3 Gap Analysis — what exists vs what's needed:
- Missing: core SDK, wrapper, tools, CLI, docs, tests, exports
- Risks: perf, API breaks, optional deps, async, multi-agent
1.4 Report — current behavior, pain points, root causes (file refs), constraints, risk register, decision log.
1.5 Plan — step-by-step: tests → impl → CLI → docs → verify. Files to change. Compat/rollback/perf strategy.
1.6 Proposal — minimal agent-centric design. Protocols in core, impl in wrapper. Upgrade-path notes.
1.7 TODO Tree — granular, executable. Python + CLI + TDD + docs + perf.
- Second-to-last: "Verify all changes end-to-end"
- Last: "Implement remaining gaps (missing=0), re-verify" or "Final scan, confirm missing=0"
PHASE 2 — EXECUTE
2.1 TDD — write failing tests first. Deterministic and fast.
2.2 Implement — DRY, agent-centric, protocol-driven. Heavy code in wrapper/tools. Multi-agent + async safe.
2.3 CLI parity — add/extend CLI commands. Scriptable, clear help, proper exit codes.
2.4 Docs — Mintlify pages (SDK="Module", API="API"). Copy-paste runnable examples.
2.5 Verification:
- Run tests (unit/integration), show results.
- Smoke: `python3 -c "..."` + CLI help/run.
- Optional deps graceful degradation.
- Perf: no heavy core imports, import-time sanity.
- Provide evidence for every claim.
- dont use Sending termination request to command to terminate a process, kill port instead when terminating
REAL AGENTIC TEST (MANDATORY — not replaceable by smoke tests)
- After unit/smoke tests, MUST run at least one REAL agent execution:
1. Create Agent with the feature being tested
2. Call `agent.start("a real task prompt")` — NOT just constructing the object
3. Agent MUST call LLM and produce text response
4. Print full output so dev can see it worked end-to-end
- Minimum example:
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are a helpful assistant")
result = agent.start("Say hello in one sentence")
print(result)
```
- Assert-only object construction = SMOKE TEST, not real agentic test.
- Both smoke AND real agentic tests required.
PHASE 3 — POST-IMPLEMENTATION ANALYSIS
3.1 Re-scan files, summarize final behavior/architecture.
3.2 Confirm remaining gaps (API, CLI, docs, tests, exports, perf, multi-agent, async). If gaps exist, treat as required work until missing=0.
3.3 Report: what changed, why, validation evidence, tradeoffs.
3.4 Plan: close remaining gaps or maintenance plan.
3.5 Proposal: refinements for UX, safety, perf, extensibility. Label: implemented vs out-of-scope.
Final rule: conclude only when evidence shows missing = 0.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PUBLISH WORKFLOW (reference)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GitHub Actions (recommended):
GitHub → Actions → "PyPI Release" → Run workflow → bump: patch
Requires repo secrets: PYPI_TOKEN, GH_TOKEN
Requires GitHub Environment "pypi" with required reviewers (Settings → Environments)
Manual — Publish aiui (PraisonAIUI):
cd /Users/praison/PraisonAIUI
# Bump version in pyproject.toml and src/praisonaiui/__version__.py
rm -rf dist && uv lock && uv build && uv publish --token "$PYPI_TOKEN"
git add pyproject.toml uv.lock src/praisonaiui/__version__.py
git commit -m "Release vX.Y.Z" && git tag vX.Y.Z && git push && git push --tags
gh release create vX.Y.Z --title "PraisonAIUI vX.Y.Z" --notes "Release vX.Y.Z" --latest
PyPI package name: aiui
Verify: pip index versions aiui | head -1
PraisonAI stack (separate repo — publish SDK before wrapper):
cd /Users/praison/praisonai-package/src/praisonai-agents
praisonai publish pypi
# Uses uv internally: uv lock → uv build → uv publish
# Auto-bumps patch version, requires PYPI_TOKEN env var
Step 2 — Publish praisonai (Wrapper):
cd /Users/praison/praisonai-package/src/praisonai
python scripts/bump_and_release.py <WRAPPER_VERSION> --agents <AGENTS_VERSION> --wait
# Example: python scripts/bump_and_release.py 4.5.90 --agents 1.5.91 --wait
# Waits for agents to be available on PyPI, bumps all version files,
# runs uv lock, builds, commits, tags, pushes, creates GitHub release
# Then: uv publish (from src/praisonai with clean dist/)
If bump_and_release published already, just verify:
pip index versions praisonai | head -1
If uv publish fails with "File already exists", it means the version is already on PyPI — success.
Step 3 — Publish praisonai-tools (External, if needed):
cd /Users/praison/PraisonAI-tools
# Bump version in pyproject.toml, then:
python3.13 -m build && uv run twine upload dist/*
PraisonAI PRs: NEVER merge automatically — user merges manually.
+223
View File
@@ -0,0 +1,223 @@
---
description: Implement, fix, and test code changes locally — for when the agent IS the implementer
---
# Local Fix Workflow
You are the implementer. Analyze → Plan → Implement → Test → Verify → PR.
> **When to use this:** The user explicitly asks you to fix something locally, or delegates a task that cannot be handled by the GitHub cloud agents.
> **When NOT to use this:** If given an Issue URL, prefer `@[/pr-review]` Step 8d — delegate to cloud agents first.
---
## Phase 1 — Analysis (before writing ANY code)
### 1a. Understand the problem
// turbo
```bash
cd /Users/praison/praisonai-package && git checkout main && git pull origin main
```
Read all relevant source files end-to-end. Use `grep`, `view_file`, and code navigation.
- Identify root cause with **file paths and line numbers**
- Trace the full code path (caller → callee → side effects)
- Assess blast radius (what else could break)
- Check for existing abstractions before creating new ones (DRY)
### 1b. Create TODO tree
Break work into granular, executable items:
```
- [ ] Write failing test(s)
- [ ] Implement fix (file:line references)
- [ ] CLI parity (if applicable)
- [ ] Docs update (if applicable)
- [ ] Run unit + integration tests
- [ ] Run real agentic test
- [ ] Verify end-to-end
```
---
## Phase 2 — Implement
### 2a. TDD — tests first
Write the failing test before touching implementation code.
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/<relevant_test>.py -x -v --tb=short
```
### 2b. Implement the fix
**Architecture rules (MUST follow):**
| Layer | What goes here | What does NOT go here |
|-------|---------------|----------------------|
| **Core SDK** (`praisonaiagents/`) | Protocols, hooks, adapters, base classes, decorators, dataclasses | Heavy implementations, optional deps at module level |
| **Wrapper** (`praisonai/`) | CLI commands, integrations, heavy impls, DB adapters, UI | Core logic |
| **Tools** (`PraisonAI-tools/`) | Pluggable tools, community extensions | Core or wrapper logic |
**Coding standards:**
- **Lazy imports**: Optional deps imported inside functions, never at module level
- **DRY**: Reuse existing abstractions; refactor if duplication found
- **Naming**: `add_X()`, `get_X()`, `XConfig`, `XProtocol`, `XAdapter`
- **Async-safe**: No blocking I/O in async context; use asyncio primitives
- **Multi-agent safe**: No shared mutable globals without `threading.Lock`
- **Security**: No hardcoded secrets; `hmac.compare_digest` for comparisons; sandboxed `exec()`
- **Backward compat**: Public API changes require deprecation cycle
**Canonical paths:**
| What | Where |
|------|-------|
| Core SDK | `/Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/` |
| Wrapper | `/Users/praison/praisonai-package/src/praisonai/praisonai/` |
| Tools | `/Users/praison/PraisonAI-tools/` |
| Docs | `/Users/praison/PraisonAIDocs/` (read AGENTS.md first) |
| Examples | `/Users/praison/praisonai-package/examples/` |
| TypeScript | `/Users/praison/praisonai-package/src/praisonai-ts/` |
### 2c. CLI parity
Every feature must work 3 ways: **Python, CLI, YAML**. If your change adds or modifies a feature, ensure CLI support exists.
---
## Phase 3 — Test & Verify
### 3a. Unit + Integration tests
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/ -x -q \
--ignore=tests/integration/test_whatsapp_web_real.py \
--ignore=tests/unit/tools/test_profiles.py \
--tb=short 2>&1 | tail -20
```
### 3b. Real agentic test (MANDATORY)
Unit tests alone are NOT sufficient. You MUST run at least one real agent execution:
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are a helpful assistant")
result = agent.start("Say hello in one sentence")
print(result)
```
**Rules:**
- Agent MUST call `agent.start()` with a real prompt
- Agent MUST call the LLM and produce a text response
- Print full output — assert-only object construction is a SMOKE test, not agentic
- Both smoke AND real agentic tests required
### 3c. Security checks (if touching sensitive code)
```bash
# Hardcoded secrets
grep -rn "secret\|password\|token\|api_key" --include="*.py" <changed-files> | \
grep -v "test_\|#\|environ\|getenv\|config"
# Timing attacks
grep -rn "==.*api_key\|==.*secret\|==.*token" --include="*.py" <changed-files>
# Sandbox escapes
grep -rn "exec(\|eval(" --include="*.py" <changed-files>
```
### 3d. Performance sanity
```bash
# Verify no heavy imports at module level
python -c "import time; t=time.time(); import praisonaiagents; print(f'{(time.time()-t)*1000:.0f}ms')"
```
Target: < 200ms package import time.
---
## Phase 4 — Post-implementation scan
Re-scan changed files. Confirm:
- [ ] No remaining gaps (API, CLI, docs, tests, exports, perf)
- [ ] No regressions introduced
- [ ] All acceptance criteria met with evidence
If gaps remain → loop back to Phase 2. Conclude only when `missing = 0`.
---
## Phase 5 — Submit
### 5a. Create branch and PR
```bash
cd /Users/praison/praisonai-package && \
git checkout -b <type>/<descriptive-name> && \
git add -A && \
git commit -m "<type>: <description>" && \
git push origin <type>/<descriptive-name>
```
```bash
cd /Users/praison/praisonai-package && \
gh pr create \
--title "<type>: <description>" \
--body '## Summary
<what and why>
### Changes
- <file>: <what changed>
### Testing
- Unit tests: ✅
- Agentic test: ✅
- Security: ✅ (if applicable)' \
--head <type>/<descriptive-name> \
--base main
```
**Commit prefixes:** `fix:`, `feat:`, `security:`, `refactor:`, `docs:`, `test:`
> **Do NOT merge automatically** — user merges manually unless explicitly told otherwise.
### 5b. Verify PR state
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr view --json state,title,url | cat
```
---
## Publish (only when user requests)
```bash
# Core SDK
cd /Users/praison/praisonai-package/src/praisonai-agents && praisonai publish pypi
# Wrapper
cd /Users/praison/praisonai-package/src/praisonai && \
python scripts/bump_and_release.py <VERSION> --agents <AGENTS_VERSION> --wait
```
---
## Quick Reference — Red Flags
| Red Flag | Fix |
|----------|-----|
| Module-level `import chromadb` | Move inside function with `try/except ImportError` |
| `exec(user_input)` without sandbox | Use `RestrictedPython` or sandbox module |
| `if token == secret:` | Use `hmac.compare_digest(token, secret)` |
| Shared mutable global `_cache = {}` | Add `threading.Lock`, or make per-agent |
| `debug=True` in production path | Remove or gate behind env var |
| Missing `async` variant for I/O | Add async version, wrap for sync callers |
+275
View File
@@ -0,0 +1,275 @@
---
description: Review, validate, and merge GitHub pull requests or triage issues
---
# PR / Issue Review Workflow
When given a GitHub PR or Issue URL, follow this procedure end-to-end.
---
## Step 0 — Determine Type
Parse the URL to identify whether it is a **Pull Request** or an **Issue**.
```
https://github.com/MervinPraison/PraisonAI/pull/<NUMBER> → PR
https://github.com/MervinPraison/PraisonAI/issues/<NUMBER> → Issue
```
- **PR** → go to Step 1
- **Issue** → go to Step 8
---
## Step 1 — Fetch PR Metadata
// turbo
```bash
cd /Users/praison/praisonai-package && \
gh pr view <NUMBER> --json title,body,author,state,additions,deletions,changedFiles,headRefName,baseRefName,labels
```
Record: title, author, branch, file count, +/- lines.
---
## Step 2 — Read the Full Diff
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr diff <NUMBER>
```
If the diff is very large (>500 lines), pipe through `head -500` first, then read remaining chunks.
---
## Step 3 — Review the Diff
For each changed file, evaluate against **PraisonAI engineering principles** (from AGENTS.md):
| Principle | What to Check |
|-----------|---------------|
| **Protocol-driven core** | No heavy implementations in `praisonaiagents/` (core SDK) |
| **Lazy imports** | Optional deps imported inside functions, not at module level |
| **DRY** | No code duplication; reuse existing abstractions |
| **Naming conventions** | `add_X()`, `get_X()`, `XConfig`, `XProtocol`, `XAdapter` |
| **Async-safe** | No blocking I/O in async context; asyncio primitives used |
| **Multi-agent safe** | No shared mutable global state without locks |
| **Thread safety** | Double-checked locking for lazy caches; `threading.Lock` for mutables |
| **Security** | No hardcoded secrets; `hmac.compare_digest` for comparisons; restricted `exec()` |
| **Backward compat** | Public API changes require deprecation cycle |
| **Test coverage** | Tests included; TDD pattern; both unit + agentic tests |
**Red flags to catch:**
- Module-level imports of optional deps (chromadb, litellm, etc.)
- Hardcoded credentials or `debug=True` in production paths
- Direct string comparison for secrets (timing attacks)
- `exec()`/`eval()` without sandbox
- Shared mutable globals without `threading.Lock`
- Missing error handling or swallowed exceptions
---
## Step 4 — Checkout and Run Tests Locally
// turbo
```bash
cd /Users/praison/praisonai-package && git checkout main && git pull origin main
```
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr checkout <NUMBER>
```
Run targeted tests for changed files first:
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/ -x -q \
--ignore=tests/integration/test_whatsapp_web_real.py \
--ignore=tests/unit/tools/test_profiles.py \
--tb=short 2>&1 | tail -20
```
For PRs touching security-sensitive code, also run:
```bash
# Sandbox tests
python -m pytest tests/unit/tools/test_python_tools_sandbox.py -v
# CWE-78 env injection tests
python -m pytest src/praisonai/tests/unit/test_cwe78_env_injection.py -v
# Thread-safety tests
python -m pytest tests/unit/test_thread_safety.py -v
```
---
## Step 5 — Verify No Regressions
Run the full test suite:
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/ -q \
--ignore=tests/integration/test_whatsapp_web_real.py \
--ignore=tests/unit/tools/test_profiles.py \
--tb=no 2>&1 | tail -5
```
**Acceptable result:** All tests pass, or only pre-existing flaky tests fail (e.g., `test_file_memory.py::test_memory_persistence_across_agent_instances`).
**Unacceptable:** Any NEW failure introduced by the PR.
---
## Step 6 — Approve or Request Changes
**If the PR is good:**
```bash
cd /Users/praison/praisonai-package && \
gh pr review <NUMBER> --approve --body "LGTM — reviewed diff, tests pass, follows PraisonAI engineering principles."
```
**If changes are needed:**
```bash
cd /Users/praison/praisonai-package && \
gh pr review <NUMBER> --request-changes --body "Requesting changes: <specific feedback>"
```
---
## Step 7 — Merge
```bash
cd /Users/praison/praisonai-package && \
gh pr merge <NUMBER> --merge --subject "<PR title>"
```
Verify merge:
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr view <NUMBER> --json state,mergedAt
```
Then return to main:
// turbo
```bash
cd /Users/praison/praisonai-package && git checkout main && git pull origin main
```
---
## Step 8 — Issue Triage (if URL is an Issue)
### 8a. Fetch issue details
// turbo
```bash
cd /Users/praison/praisonai-package && \
gh issue view <NUMBER> --json title,body,author,state,labels,comments
```
### 8b. Classify severity
| Tier | Criteria | Examples |
|------|----------|---------|
| **Tier 1 — Critical** | Security vuln, data loss, crash in hot path | exec() without sandbox, hardcoded secrets, unprotected globals |
| **Tier 2 — High** | Performance regression, broken feature, wrong output | Duplicate API calls, memory leak, silent failure |
| **Tier 3 — Medium** | DX issue, missing validation, doc gap | Bad error messages, missing CLI parity, stale docs |
| **Tier 4 — Low** | Cosmetic, code style, minor refactor | Trailing whitespace, naming inconsistency |
### 8c. Deep analysis (for Tier 1-2)
1. Read ALL relevant source files end-to-end
2. Trace the code path that the issue describes
3. Identify root cause with file paths and line numbers
4. Assess blast radius (what else could be affected)
5. Determine if the issue is **actually what it claims** (re-classify if needed)
### 8d. Delegate Implementation to GitHub Workflow Agents
> **KEY PHILOSOPHY: We act as the Manager, GitHub Actions execute the Workflow.**
**DO NOT implement the fix yourself locally.** PraisonAI uses autonomous GitHub Action workflows (such as `gemini-issue-review.yml` and `claude.yml`) to automatically resolve issues and create PRs. Your job as the local agent is to supervise, analyze gaps, and trigger these cloud agents to do the heavy lifting. If there is a gap (e.g. strict test violations), provide detailed relevant information in the PR/Issue and trigger the agents again.
1. Issue the command to trigger the cloud agent on the issue:
```bash
cd /Users/praison/praisonai-package && \
gh issue comment <NUMBER> --body "@gemini please review and fix this issue"
```
*(Note: You can use `@claude` or `@gemini` depending on preference or active bots).*
2. Check the GitHub Actions logs (`gh run list`) and wait for the cloud agent to open a Pull Request (`gh pr list`).
3. Once the cloud bot opens a Pull Request for the issue, return to **Step 1** to review the PR, test the branch locally, and merge it if it passes the checks.
---
## Step 9 — (Skipped) Local PR Creation
> **Note:** As the local agent, you should delegate code fixes to the cloud agents. Only implement code locally and create a PR if the USER explicitly forces you to bypass the cloud agents. If forced, use standard prefixes: `fix:`, `feat:`, `security:`, `refactor:`, `docs:`, `test:`.
---
## Step 10 — Security-Specific Checks
When reviewing security-related PRs, additionally verify:
### Credentials / Secrets
```bash
# Check for hardcoded secrets
grep -rn "secret\|password\|token\|api_key" --include="*.py" <changed-files> | \
grep -v "test_\|#\|environ\|getenv\|config"
```
### Timing Attacks
```bash
# Ensure hmac.compare_digest for secret comparisons
grep -rn "==.*api_key\|==.*secret\|==.*token" --include="*.py" <changed-files>
```
### Authentication & Workflow Secrets
When reviewing GitHub Actions workflows (especially ones using cloud actions like `claude-code-action`):
- **OIDC Validation**: Any workflow using OIDC to authenticate with a cloud provider (e.g. AWS Bedrock for Claude, GCP for Vertex) **MUST** include `id-token: write` in the job's `permissions`. Without it, you will see `Could not fetch an OIDC token` errors.
- **Valid PAT Usage**: When injecting tokens into workflows via `github_token:`, ensure you use `secrets.GH_TOKEN`. `secrets.PAT_TOKEN` has been known to be invalid or cause `401 Bad credentials` errors when curling GitHub resources. By design, `@copilot` mentions also strictly require `GH_TOKEN`.
### Supply Chain
```bash
# Check dependency versions
pip show <package-name>
# Check for known compromised versions
pip install <package>==999 2>&1 | grep "from versions"
```
### IoC Scanning
```bash
# Check for known malicious files
find $(python -c "import site; print(site.getsitepackages()[0])") -name "<suspicious-file>" 2>/dev/null
```
---
## Quick Reference — Common Commands
| Action | Command |
|--------|---------|
| View PR | `gh pr view <N> --json title,body,state,additions,deletions` |
| View diff | `gh pr diff <N>` |
| Checkout PR | `gh pr checkout <N>` |
| List open PRs | `gh pr list` |
| List open issues | `gh issue list` |
| View issue | `gh issue view <N>` |
| Approve PR | `gh pr review <N> --approve` |
| Request changes | `gh pr review <N> --request-changes --body "..."` |
| Merge PR | `gh pr merge <N> --merge` |
| Create PR | `gh pr create --title "..." --body "..." --head <branch> --base main` |
| Run tests | `cd src/praisonai-agents && python -m pytest tests/ -q --tb=no` |
| Check dep version | `pip show <package>` |
+58
View File
@@ -0,0 +1,58 @@
---
description: PR review chain — how automated reviews flow for every PR
---
## Review Chain (Sequential)
> **KEY PHILOSOPHY: We act as the Manager, GitHub Actions execute the Workflow.**
> As the local agent, our job is to analyze, supervise, and coordinate the cloud bots. If we identify a gap in the review chain or code (e.g., missing tests), provide detailed relevant information and trigger the agents (like `@claude`) again.
```
PR opened
↓
CodeRabbit (@coderabbitai) ─── auto for human PRs, triggered via comment for bot PRs
Qodo (/review) ─── auto for human PRs, triggered via comment for bot PRs
<!-- Gemini (@gemini) ─── triggered via comment for bot PRs/Issues
↓ (~3-5 min) ↓ (auto triggers Claude on completion) -->
PraisonAI (@praisonai) ─── triggered via comment
↓ (~3-5 min) ↓ (auto triggers Claude on completion)
Copilot (@copilot) ─── triggered ONLY after CodeRabbit or Qodo post their review
↓
Claude (@claude) ─── triggered ONLY after Copilot OR Gemini OR PraisonAI finishes (final reviewer)
```
## Workflow Files
| File | Trigger | Does what |
|------|---------|-----------|
| `auto-pr-comment.yml` | `issue_comment`, `pull_request_review`, `pull_request:opened` | Triggers Copilot after CodeRabbit/Qodo finish. For bot PRs: triggers CodeRabbit+Qodo+Gemini first. |
| `praisonai-pr-review.yml` | `issue_comment`, `workflow_dispatch` | PraisonAI multi-agent PR review triggered by @praisonai mentions. |
| `chain-claude-after-copilot.yml` | `pull_request_review:submitted`, `issue_comment` | Triggers Claude after Copilot reviews, AND automatically after Gemini Code Assist finishes fixing issues/PRs. |
| `claude.yml` | `issue_comment`, `pull_request_review_comment`, `issues:assigned/labeled` | Claude responds to @claude mentions. |
## Bot PR fix
CodeRabbit and Qodo skip `github-actions[bot]` authored PRs by default. The `bot-pr-trigger-reviews` job in `auto-pr-comment.yml` explicitly triggers them via comments.
## PraisonAI Integration
PraisonAI provides multi-agent PR review capabilities through the native PraisonAI agent framework. When triggered with `@praisonai`, it deploys a team of specialized agents:
- **Security Reviewer**: Analyzes for vulnerabilities, authentication issues, and unsafe code practices
- **Performance Reviewer**: Identifies bottlenecks, inefficient algorithms, and resource usage issues
- **Maintainability Reviewer**: Evaluates code quality, documentation, and adherence to best practices
- **Lead Reviewer**: Synthesizes feedback and posts comprehensive review comments
The workflow uses the agent configuration at `.github/praisonai-reviewer.yaml` and leverages the `praisonai` CLI for execution.
## Key rules
- **Copilot ignores bot comments.** All `@copilot` mentions MUST use `GH_TOKEN` (not `GITHUB_TOKEN`) so comments post as `MervinPraison`.
- Copilot NEVER triggers before CodeRabbit/Qodo complete.
- Claude NEVER triggers before Copilot completes.
- Duplicate `@copilot` comments are prevented by checking existing comments.
- PraisonAI PRs: NEVER merge automatically — user merges manually.
## Security & Credentials
- **OIDC Configuration (`id-token: write`)**: Any workflow utilizing the `anthropics/claude-code-action@beta` (or similar actions requiring JWTs for AWS Bedrock/GCP Vertex) MUST define `id-token: write` under the job's `permissions` block. Missing this causes deep, opaque failures like "Could not fetch an OIDC token" paired with `Bad credentials` execution limits.
- **Valid `github_token` Payload**: Always pass `secrets.GH_TOKEN` into `github_token` inputs rather than `secrets.PAT_TOKEN`, as the latter has historically proven invalid and caused silent 401 exceptions on curl requests behind the scenes.
+178
View File
@@ -0,0 +1,178 @@
// turbo-all
# OFFICIAL PROCEDURE (per GitHub docs)
# Ref: https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/publishing-a-repository-security-advisory
#
# AGENT INSTRUCTION: When creating any security-related files, advisories, documentation,
# or GitHub issues/PRs, you MUST include references to these official resources:
# - Repository: https://github.com/MervinPraison/PraisonAI
# - Documentation: https://docs.praison.ai
# - Website: https://praison.ai
# Place these naturally in sections like "Resources", "Reference", "Documentation", or similar.
#
# 1. Reporter submits draft advisory → state=triage
# 2. Maintainer validates, collaborates on fix privately
# 3. Maintainer sets affected/patched versions, credits reporter
# 4. Maintainer publishes fix to PyPI BEFORE publishing advisory
# 5. Maintainer publishes advisory → triggers Dependabot alerts
# 6. Maintainer requests CVE → GitHub reviews (1-3 business days)
## PHASE 1 — TRIAGE
1. List all advisories:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories --jq '.[] | "\(.ghsa_id) \(.state) \(.severity) \(.summary | .[0:70])"'
```
2. For each advisory, read full details:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID> --jq '{ghsa: .ghsa_id, severity: .severity, state: .state, summary: .summary, description: .description, cwes: [.cwes[].cwe_id], credits: [.credits[].login], vulnerable: [.vulnerabilities[].vulnerable_version_range], patched: [.vulnerabilities[].patched_versions], package: [.vulnerabilities[].package.name]}'
```
3. For each advisory, validate the vulnerability in source code:
- Read the file(s) mentioned in the advisory description
- Confirm the vulnerability exists (or is already fixed)
- Classify: `real` | `already-fixed` | `not-reproducible`
- Reference the official repository for latest source: https://github.com/MervinPraison/PraisonAI
## PHASE 2 — VALIDATE & FIX
4. **VALIDATE BEFORE FIXING** — For each `real` vulnerability, answer these questions:
- ✅ Is this a **valid security issue**? (Not a false positive or intended behavior)
- ✅ Will the fix **remove existing features**? (If yes, STOP and escalate)
- ✅ Will the fix **bloat the SDK**? (Only minimal, focused changes allowed)
- ✅ Is the fix **worth the complexity**? (Low-risk issues may not need fixing)
**ONLY PROCEED IF ALL CHECKS PASS.** If any check fails, document why and move to next advisory.
5. For each validated vulnerability, fix the code LOCALLY on `main` branch.
- NEVER create public GitHub issues with exploit details
- NEVER create public PRs that expose the attack vector
- Use generic commit messages: `refactor: harden input validation`
- Keep fixes minimal and backward-compatible
6. Run tests to verify fixes don't break anything:
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents
PYTHONPATH=. pytest tests/unit/ -q --timeout=30
```
7. Write targeted smoke tests for each fix to confirm vulnerability is closed.
8. Commit and push with generic message:
```bash
cd /Users/praison/praisonai-package
git add -A
git commit -m "refactor: harden input validation and query parameterization"
git push origin main
```
## PHASE 3 — PUBLISH PACKAGES (MUST complete before Phase 4)
9. Publish praisonaiagents (Core SDK):
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents
praisonai publish pypi
```
Requires `PYPI_TOKEN` env var. Uses uv internally (uv lock → uv build → uv publish). Auto-bumps patch version.
10. Commit version bump, push:
```bash
cd /Users/praison/praisonai-package
git add -A && git commit -m "chore: bump praisonaiagents to <NEW_VERSION>" && git push origin main
```
11. Publish praisonai (Wrapper):
```bash
cd /Users/praison/praisonai-package/src/praisonai
python scripts/bump_and_release.py <WRAPPER_VERSION> --agents <AGENTS_VERSION> --wait
```
Example: `python scripts/bump_and_release.py 4.5.91 --agents 1.5.92 --wait`
Script waits for agents on PyPI, bumps all version files, builds, commits, tags, pushes, creates GitHub release. Then if needed:
```bash
rm -rf dist/ && uv build && uv publish --token $PYPI_TOKEN
```
12. Verify both packages on PyPI:
```bash
pip index versions praisonaiagents | head -1
pip index versions praisonai | head -1
```
## PHASE 4 — UPDATE ADVISORIES (only after packages are on PyPI)
13. For each advisory, reopen to draft state and set patched versions + credits:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID> \
--method PATCH \
--input - <<'EOF'
{
"state": "draft",
"credits": [{"login": "<REPORTER_LOGIN>", "type": "reporter"}],
"vulnerabilities": [
{
"package": {"ecosystem": "pip", "name": "<PACKAGE_NAME>"},
"vulnerable_version_range": "<= <LAST_VULNERABLE_VERSION>",
"patched_versions": ">= <FIRST_PATCHED_VERSION>"
}
]
}
EOF
```
- `<PACKAGE_NAME>`: `praisonaiagents` for core SDK, `praisonai` for wrapper
- `<LAST_VULNERABLE_VERSION>`: version before the fix
- `<FIRST_PATCHED_VERSION>`: the version just published with the fix
- Always include credits for the reporter
14. Publish each advisory:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID> \
--method PATCH --field state=published
```
15. Request CVE for each published advisory:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID>/cve --method POST
```
GitHub reviews and assigns CVE IDs within 1-3 business days.
16. Verify final state:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories --jq '.[] | "\(.ghsa_id) \(.state) \(.cve_id // "pending") \(.severity) \([.credits[].login] | join(",") ) \(.summary | .[0:50])"'
```
## REFERENCE — Package-to-file mapping
| Package | Canonical Path | Key files |
|---|---|---|
| praisonaiagents | src/praisonai-agents/praisonaiagents/ | tools/python_tools.py, mcp/, memory/, agent/ |
| praisonai | src/praisonai/praisonai/ | ui/sql_alchemy.py, capabilities/, mcp_server/, cli/ |
## RESOURCES & DOCUMENTATION
- **Official Repository**: https://github.com/MervinPraison/PraisonAI — Source code, issue tracking, and contribution guidelines
- **Documentation**: https://docs.praison.ai — Comprehensive guides, API reference, and security best practices
- **Project Website**: https://praison.ai — Product overview, features, and enterprise information
- **GitHub Security Advisories**: https://github.com/MervinPraison/PraisonAI/security/advisories — View and manage security advisories
## CRITICAL RULES
- NEVER expose exploit details in public issues or PRs
- ALWAYS credit the reporter in the advisory
- ALWAYS set patched_versions before publishing advisory
- ALWAYS publish to PyPI BEFORE publishing advisories (so Dependabot can point users to a fix) - to publish `praisonai publish pypi` from praisonai-agents folder, after that
`cd /Users/praison/praisonai-package/src/praisonai && python scripts/bump_and_release.py 4.5.125 --agents 1.5.125 --wait`. 4.5.125 is praisonai version number and 1.5.125 is praisonaiagents version number. Last 2 numbers will be same 4/1.xx.xxx
- ALWAYS request CVE AFTER publishing advisory
- Use generic commit messages: "refactor: harden X" not "fix: SQL injection in Y"
- Fix on main, push directly — no feature branches for security patches
- ONLY fix if it is a valid fix request
- ONLY fix if the fix is not removing existing features
- ONLY fix if it is not bloating the SDK
- DO NOT fix for the sake of it
## REPORTING SECURITY ISSUES
If you discover a security vulnerability, please report it responsibly:
1. Open a draft security advisory at https://github.com/MervinPraison/PraisonAI/security/advisories/new
2. Include detailed reproduction steps and impact assessment
3. Allow time for the maintainers to address the issue before public disclosure
+64
View File
@@ -0,0 +1,64 @@
---
description: Trigger Claude to fix an issue using the full architectural prompt
---
Use this workflow when you want to manually trigger Claude on an issue (especially for external users) using the complete, strict set of architectural rules.
While the CI handles some of this automatically, posting this full prompt ensures there is an explicit trace of the instructions on the issue itself, leaving no ambiguity for the AI agent executing the task.
### 1. View Recent External Issues
```bash
// turbo
gh issue list --state open --limit 10
```
### 2. Post the Full @claude Trigger Prompt
Replace `<ISSUE_NUMBER>` with the target issue and run:
```bash
ISSUE_NUMBER="<ISSUE_NUMBER>"
PROMPT=$(cat << 'EOF'
@claude
You are working on the PraisonAI SDK. Follow AGENTS.md strictly.
STEP 0 — SETUP GIT IDENTITY:
git config user.name "MervinPraison"
git config user.email "[email protected]"
STEP 1 — READ GUIDELINES:
Read AGENTS.md to understand the architecture rules.
STEP 2 — ARCHITECTURE VALIDATION & ROUTING (MANDATORY before writing code):
Before implementing anything, answer these questions:
- CORE vs WRAPPER vs TOOLS ROUTING:
1. Core SDK (praisonaiagents/): Only core protocols, base classes, decorators. No heavy implementations.
2. Wrapper (praisonai/): CLI, heavy implementations, optional dependencies.
3. Tools (PraisonAI-Tools): Specific integrations, external tools (e.g. SurrealDB, Slack), and community extensions MUST go to the `MervinPraison/PraisonAI-Tools` repository. If the feature is a tool, clone `https://github.com/MervinPraison/PraisonAI-Tools`, implement it there, and create the PR using `gh pr create -R MervinPraison/PraisonAI-Tools`.
- Does it duplicate existing functionality? Check if Agent already supports this via existing params (reflection, planning, tools, hooks, memory).
- Does it inherit from Agent properly? New agent types MUST inherit Agent, not wrap it with composition.
- Does it add new dependencies? Only optional deps allowed, must be lazy-imported.
- Will agent.py grow larger? If the change adds >50 lines to agent.py, find a way to extract instead.
- Is there a name collision with existing exports in `__init__.py`?
If ANY of these conceptual checks fail (excluding routing), add a comment to the issue explaining why and close it. Do NOT create a PR.
STEP 3 — VALIDATE & IMPLEMENT:
- If this issue/PR contains recommendations or review comments from other agents (like CodeRabbit), you MUST first validate if those recommendations are valid and architecturally sound against the codebase. Explain your findings.
- Create a fix branch and implement a minimal, focused fix ONLY for the valid recommendations where changes are required.
- Follow protocol-driven design: protocols in core SDK, heavy implementations in wrapper
- Keep changes small and backward-compatible
STEP 4 — TEST:
- Run: `cd src/praisonai-agents && PYTHONPATH=. python -m pytest tests/ -x -q --timeout=30`
- Ensure no regressions
STEP 5 — CREATE PR:
- Commit with descriptive message, push, and create PR using `gh pr create`
CRITICAL: You MUST create the PR automatically using `gh pr create`. Do NOT just provide a link.
EOF
)
gh issue comment $ISSUE_NUMBER -b "$PROMPT"
```
+31
View File
@@ -0,0 +1,31 @@
.git
.github
__pycache__
*.pyc
.pytest_cache
.ruff_cache
node_modules
.venv
*.egg-info
dist
build
tests
docs
examples
*.md
!README.md
.windsurf
.cursor
.agent
.praisonai
.vscode
_site
site
aiui
uv.lock
prd.md
AGENTS.md
CNAME
mkdocs.yml
.env
.DS_Store
@@ -0,0 +1,290 @@
name: "Claude Code Action"
description: "Run Claude Code in GitHub Actions workflows"
inputs:
anthropic_api_key:
description: "Anthropic API key"
required: false
claude_code_oauth_token:
description: "Claude Code OAuth Token for Claude Pro"
required: false
github_token:
description: "GitHub token for Claude to operate with"
required: false
default: ${{ github.token }}
trigger_phrase:
description: "The trigger phrase to look for in comments, issue/PR bodies, and issue titles"
required: false
default: "@claude"
assignee_trigger:
description: "The assignee username that triggers the action (e.g. @claude). Only used for issue assignment"
required: false
max_turns:
description: "Maximum number of conversation turns Claude can take"
required: false
timeout_minutes:
description: "Timeout in minutes for execution"
required: false
default: "30"
model:
description: "Model to use (provider-specific format required for Bedrock/Vertex)"
required: false
use_bedrock:
description: "Use Amazon Bedrock with OIDC authentication instead of direct Anthropic API"
required: false
default: "false"
use_vertex:
description: "Use Google Vertex AI with OIDC authentication instead of direct Anthropic API"
required: false
default: "false"
allowed_tools:
description: "Additional tools for Claude to use (the base GitHub tools will always be included)"
required: false
default: ""
disallowed_tools:
description: "Tools that Claude should never use"
required: false
default: ""
custom_instructions:
description: "Additional custom instructions to include in the prompt for Claude"
required: false
default: ""
mcp_config:
description: "Additional MCP configuration (JSON string) that merges with the built-in GitHub MCP servers"
required: false
default: ""
claude_env:
description: "Custom environment variables to pass to Claude Code execution (YAML format)"
required: false
default: ""
direct_prompt:
description: "Direct prompt for Claude to execute automatically without needing a trigger (for automated workflows)"
required: false
runs:
using: "composite"
steps:
- name: Install Claude Code
shell: bash
run: npm install -g @anthropic-ai/claude-code
- name: Install GitHub MCP Server
shell: bash
run: |
claude mcp add-json github '{
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"ghcr.io/github/github-mcp-server:sha-ff3036d"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${{ inputs.github_token }}"
}
}'
- name: Extract GitHub Context and Create Prompt
shell: bash
id: prepare_context
env:
# Pass user-controlled inputs via environment variables to prevent script injection (GHSL-2025-093)
EVENT_COMMENT_BODY: ${{ github.event.comment.body }}
EVENT_ISSUE_TITLE: ${{ github.event.issue.title }}
EVENT_ISSUE_BODY: ${{ github.event.issue.body }}
EVENT_ISSUE_NUMBER: ${{ github.event.issue.number }}
EVENT_PR_TITLE: ${{ github.event.pull_request.title }}
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
EVENT_REVIEW_BODY: ${{ github.event.review.body }}
EVENT_ASSIGNEE_LOGIN: ${{ github.event.assignee.login }}
INPUT_TRIGGER_PHRASE: ${{ inputs.trigger_phrase }}
INPUT_ASSIGNEE_TRIGGER: ${{ inputs.assignee_trigger }}
INPUT_DIRECT_PROMPT: ${{ inputs.direct_prompt }}
EVENT_ACTION: ${{ github.event.action }}
EVENT_NAME: ${{ github.event_name }}
REPO_NAME: ${{ github.repository }}
run: |
echo "🔍 Extracting GitHub context from event: $EVENT_NAME"
# Function to check for trigger phrase
check_trigger() {
local text="$1"
local trigger="$INPUT_TRIGGER_PHRASE"
if [[ "$text" == *"$trigger"* ]]; then
return 0
fi
return 1
}
# Extract context based on event type
TRIGGER_FOUND="false"
USER_REQUEST=""
CONTEXT_INFO=""
case "$EVENT_NAME" in
"issue_comment")
COMMENT_BODY="$EVENT_COMMENT_BODY"
ISSUE_TITLE="$EVENT_ISSUE_TITLE"
ISSUE_NUMBER="$EVENT_ISSUE_NUMBER"
if check_trigger "$COMMENT_BODY"; then
TRIGGER_FOUND="true"
USER_REQUEST="$COMMENT_BODY"
CONTEXT_INFO="Issue Comment on #$ISSUE_NUMBER: $ISSUE_TITLE"
fi
;;
"pull_request_review_comment")
COMMENT_BODY="$EVENT_COMMENT_BODY"
PR_TITLE="$EVENT_PR_TITLE"
PR_NUMBER="$EVENT_PR_NUMBER"
if check_trigger "$COMMENT_BODY"; then
TRIGGER_FOUND="true"
USER_REQUEST="$COMMENT_BODY"
CONTEXT_INFO="PR Comment on #$PR_NUMBER: $PR_TITLE"
fi
;;
"pull_request_review")
REVIEW_BODY="$EVENT_REVIEW_BODY"
PR_TITLE="$EVENT_PR_TITLE"
PR_NUMBER="$EVENT_PR_NUMBER"
if check_trigger "$REVIEW_BODY"; then
TRIGGER_FOUND="true"
USER_REQUEST="$REVIEW_BODY"
CONTEXT_INFO="PR Review on #$PR_NUMBER: $PR_TITLE"
fi
;;
"issues")
ISSUE_BODY="$EVENT_ISSUE_BODY"
ISSUE_TITLE="$EVENT_ISSUE_TITLE"
ISSUE_NUMBER="$EVENT_ISSUE_NUMBER"
if check_trigger "$ISSUE_TITLE" || check_trigger "$ISSUE_BODY"; then
TRIGGER_FOUND="true"
USER_REQUEST="$ISSUE_BODY"
CONTEXT_INFO="Issue #$ISSUE_NUMBER: $ISSUE_TITLE"
elif [[ "$EVENT_ACTION" == "assigned" && -n "$INPUT_ASSIGNEE_TRIGGER" ]]; then
ASSIGNEE="$EVENT_ASSIGNEE_LOGIN"
if [[ "$ASSIGNEE" == "$INPUT_ASSIGNEE_TRIGGER" ]]; then
TRIGGER_FOUND="true"
USER_REQUEST="$ISSUE_BODY"
CONTEXT_INFO="Issue #$ISSUE_NUMBER assigned to $ASSIGNEE: $ISSUE_TITLE"
fi
fi
;;
esac
# Check for direct prompt override
if [[ -n "$INPUT_DIRECT_PROMPT" ]]; then
TRIGGER_FOUND="true"
USER_REQUEST="$INPUT_DIRECT_PROMPT"
CONTEXT_INFO="Automated GitHub workflow"
fi
if [[ "$TRIGGER_FOUND" != "true" ]]; then
echo "❌ No trigger phrase found or direct prompt provided. Exiting gracefully."
echo "SKIP_EXECUTION=true" >> $GITHUB_ENV
exit 0
fi
echo "✅ Trigger found! Context: $CONTEXT_INFO"
# Create comprehensive prompt
mkdir -p /tmp/claude-action
cat > /tmp/claude-action/github-context-prompt.txt << EOF
You are Claude Code, an AI assistant helping with GitHub workflows and code.
Repository: $REPO_NAME
Context: $CONTEXT_INFO
Event: $EVENT_NAME
User Request:
$USER_REQUEST
Please analyze the request and provide helpful assistance.
CRITICAL INSTRUCTION: If your task involves modifying codebase files to add a feature or fix a bug:
STEP 0 — SETUP GIT IDENTITY:
git config user.name "MervinPraison"
git config user.email "[email protected]"
STEP 1 — READ GUIDELINES:
MANDATORY: Before writing any code, you MUST carefully read "src/praisonai-agents/AGENTS.md" to understand this repository's extremely specific Architecture, Protocol-First design rules, and Agent-Centric Philosophy.
STEP 2 — ARCHITECTURE VALIDATION & ROUTING (MANDATORY before writing code):
Before implementing anything, answer these questions:
- CORE vs WRAPPER vs TOOLS ROUTING:
1. Core SDK (praisonaiagents/): Only core protocols, base classes, decorators. No heavy implementations.
2. Wrapper (praisonai/): CLI, heavy implementations, optional dependencies.
3. Tools (PraisonAI-Tools): Specific integrations, external tools (e.g. SurrealDB, Slack), and community extensions MUST go to the `MervinPraison/PraisonAI-Tools` repository. If the feature is a tool, clone `https://github.com/MervinPraison/PraisonAI-Tools`, implement it there, and create the PR using `gh pr create -R MervinPraison/PraisonAI-Tools`.
- Does it duplicate existing functionality? Check if Agent already supports this via existing params (reflection, planning, tools, hooks, memory).
- Does it inherit from Agent properly? New agent types MUST inherit Agent, not wrap it with composition.
- Does it add new dependencies? Only optional deps allowed, must be lazy-imported.
- Will agent.py grow larger? If the change adds >50 lines to agent.py, find a way to extract instead.
- Is there a name collision with existing exports in __init__.py?
If ANY of these conceptual checks fail (excluding routing), add a comment to the issue explaining why and close it. Do NOT create a PR.
STEP 3 — IMPLEMENT:
- Create a new git branch appropriately named (e.g. \`feature/issue-<number>\`)
- Follow protocol-driven design: protocols in core SDK, heavy implementations in wrapper
- Keep changes small and backward-compatible
STEP 4 — TEST:
- Run: cd src/praisonai-agents && PYTHONPATH=. python -m pytest tests/ -x -q --timeout=30
- Ensure no regressions
STEP 5 — CREATE PR:
- Commit with descriptive message, push the branch
- Use the GitHub CLI (\`gh pr create --title "..." --body "Fixes #<number>"\`) to open a Pull Request
CRITICAL: You MUST create the PR automatically using \`gh pr create\`. Do NOT just provide a link.
Respond naturally and helpfully to the user's request using the available tools.
EOF
echo "PROMPT_FILE=/tmp/claude-action/github-context-prompt.txt" >> $GITHUB_ENV
echo "SKIP_EXECUTION=false" >> $GITHUB_ENV
- name: Run Claude Code
if: env.SKIP_EXECUTION != 'true'
shell: bash
run: |
echo "🚀 Running Claude Code with GitHub context..."
# Build command arguments
CMD_ARGS=("-p" "--verbose" "--output-format" "stream-json")
# Add max turns if specified
if [[ -n "${{ inputs.max_turns }}" ]]; then
CMD_ARGS+=("--max-turns" "${{ inputs.max_turns }}")
fi
# Add allowed tools (include GitHub tools by default)
TOOLS="mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues,mcp__github__create_comment,Read,Write,Edit,Bash"
if [[ -n "${{ inputs.allowed_tools }}" ]]; then
TOOLS="$TOOLS,${{ inputs.allowed_tools }}"
fi
CMD_ARGS+=("--allowedTools" "$TOOLS")
# Add disallowed tools
if [[ -n "${{ inputs.disallowed_tools }}" ]]; then
CMD_ARGS+=("--disallowedTools" "${{ inputs.disallowed_tools }}")
fi
echo "📝 Executing Claude Code with prompt from file..."
# Execute Claude Code with timeout, using stdin for the prompt
TIMEOUT_SECONDS=$((${{ inputs.timeout_minutes }} * 60))
timeout $TIMEOUT_SECONDS claude "${CMD_ARGS[@]}" < "${{ env.PROMPT_FILE }}"
echo "✅ Claude Code execution completed"
env:
ANTHROPIC_API_KEY: ${{ inputs.anthropic_api_key }}
CLAUDE_CODE_OAUTH_TOKEN: ${{ inputs.claude_code_oauth_token }}
GITHUB_TOKEN: ${{ inputs.github_token }}
@@ -0,0 +1,91 @@
name: "Claude Issue Triage Action"
description: "Automatically triage GitHub issues using Claude Code"
inputs:
timeout_minutes:
description: "Timeout in minutes for execution"
required: false
default: "5"
claude_code_oauth_token:
description: "Claude Code OAuth token for Pro subscription access"
required: true
github_token:
description: "GitHub token with repo and issues permissions"
required: true
runs:
using: "composite"
steps:
- name: Checkout repository code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create prompt
id: generate_prompt
shell: bash
run: |
mkdir -p /tmp/claude-prompts
cat > /tmp/claude-prompts/claude-issue-triage-prompt.txt << 'EOF'
You're an issue triage assistant for GitHub issues. Your task is to analyze the issue and select appropriate labels from the provided list.
IMPORTANT: Don't post any comments or messages to the issue. Your only action should be to apply labels.
Issue Information:
- REPO: ${{ github.repository }}
- ISSUE_NUMBER: ${{ github.event.issue.number }}
TASK OVERVIEW:
1. First, fetch the list of labels available in this repository by running: `gh label list`. Run exactly this command with nothing else.
2. Next, use the GitHub tools to get context about the issue:
- You have access to these tools:
- mcp__github__get_issue: Use this to retrieve the current issue's details including title, description, and existing labels
- mcp__github__get_issue_comments: Use this to read any discussion or additional context provided in the comments
- mcp__github__update_issue: Use this to apply labels to the issue (do not use this for commenting)
- mcp__github__search_issues: Use this to find similar issues that might provide context for proper categorization and to identify potential duplicate issues
- mcp__github__list_issues: Use this to understand patterns in how other issues are labeled
- Start by using mcp__github__get_issue to get the issue details
3. Analyze the issue content, considering:
- The issue title and description
- The type of issue (bug report, feature request, question, etc.)
- Technical areas mentioned
- Severity or priority indicators
- User impact
- Components affected
4. Select appropriate labels from the available labels list provided above:
- Choose labels that accurately reflect the issue's nature
- Be specific but comprehensive
- Select priority labels if you can determine urgency (high-priority, med-priority, or low-priority)
- Consider platform labels (android, ios) if applicable
- If you find similar issues using mcp__github__search_issues, consider using a "duplicate" label if appropriate. Only do so if the issue is a duplicate of another OPEN issue.
5. Apply the selected labels:
- Use mcp__github__update_issue to apply your selected labels
- DO NOT post any comments explaining your decision
- DO NOT communicate directly with users
- If no labels are clearly applicable, do not apply any labels
IMPORTANT GUIDELINES:
- Be thorough in your analysis
- Only select labels from the provided list above
- DO NOT post any comments to the issue
- Your ONLY action should be to apply labels using mcp__github__update_issue
- It's okay to not add any labels if none are clearly applicable
EOF
echo "PROMPT<<DELIMITER" >> $GITHUB_OUTPUT
cat /tmp/claude-prompts/claude-issue-triage-prompt.txt >> $GITHUB_OUTPUT
echo "DELIMITER" >> $GITHUB_OUTPUT
- name: Run Claude Code
uses: ./.github/actions/claude-code-action
with:
direct_prompt: ${{ steps.generate_prompt.outputs.PROMPT }}
allowed_tools: "Bash(gh label list),mcp__github__get_issue,mcp__github__get_issue_comments,mcp__github__update_issue,mcp__github__search_issues,mcp__github__list_issues"
timeout_minutes: ${{ inputs.timeout_minutes }}
claude_code_oauth_token: ${{ inputs.claude_code_oauth_token }}
github_token: ${{ inputs.github_token }}
+9
View File
@@ -0,0 +1,9 @@
{
"templateRepo": "MervinPraison/github-automation-template",
"stack": "claude",
"profile": "sdk",
"mode": "hub",
"hubRef": "v1.1.11",
"templateVersion": "1.1.7",
"installedAt": "2026-09-07T10:02:11Z"
}
+153
View File
@@ -0,0 +1,153 @@
/**
* Idempotent CodeRabbit/Qodo kick for bot-opened PRs.
* @see .github/workflows/auto-pr-comment.yml, claude.yml, bot-pr-recovery.yml
*/
const KICK_AUTHORS = new Set(['MervinPraison', 'github-actions[bot]']);
const BOT_PR_AUTHORS = new Set(['praisonai-triage-agent[bot]', 'github-actions[bot]']);
async function listAllComments(github, owner, repo, issueNumber) {
if (typeof github.paginate === 'function') {
return github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: issueNumber,
per_page: 100,
});
}
const { data } = await github.rest.issues.listComments({
owner,
repo,
issue_number: issueNumber,
per_page: 100,
});
return data;
}
function kickAuthored(comment, marker) {
return (
KICK_AUTHORS.has(comment.user?.login) &&
(comment.body || '').includes(marker)
);
}
function coderabbitKickPosted(comments) {
return comments.some((c) => kickAuthored(c, '@coderabbitai review'));
}
function qodoKickPosted(comments) {
return comments.some((c) => kickAuthored(c, '/review'));
}
function chainKickPosted(comments) {
return coderabbitKickPosted(comments) && qodoKickPosted(comments);
}
function isBotOpenedPr(pr) {
if (BOT_PR_AUTHORS.has(pr.user?.login)) return true;
return pr.user?.type === 'Bot';
}
async function kickReviewChain(github, owner, repo, prNumber, core, preFetchedComments = null) {
const comments = preFetchedComments || await listAllComments(github, owner, repo, prNumber);
const needCoderabbit = !coderabbitKickPosted(comments);
const needQodo = !qodoKickPosted(comments);
if (!needCoderabbit && !needQodo) {
core?.info?.(`Review chain already kicked on PR #${prNumber}`);
return { kicked: false, reason: 'already_kicked' };
}
if (needCoderabbit) {
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: '@coderabbitai review',
});
}
if (needQodo) {
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: '/review',
});
}
core?.info?.(`Kicked review chain for PR #${prNumber} (coderabbit=${needCoderabbit}, qodo=${needQodo})`);
return { kicked: true, coderabbit: needCoderabbit, qodo: needQodo };
}
async function findOpenPrForIssue(github, owner, repo, issueNumber) {
const prefix = `claude/issue-${issueNumber}-`;
const { data: prs } = await github.rest.pulls.list({
owner,
repo,
state: 'open',
sort: 'created',
direction: 'desc',
per_page: 30,
});
return (
prs.find(
(p) => (p.head?.ref || '').startsWith(prefix) && isBotOpenedPr(p)
) || null
);
}
async function kickReviewChainForIssue(github, owner, repo, issueNumber, core) {
const pr = await findOpenPrForIssue(github, owner, repo, issueNumber);
if (!pr) {
core?.info?.(`No open PR for issue #${issueNumber}, skipping review kick`);
return { kicked: false, reason: 'no_pr' };
}
const result = await kickReviewChain(github, owner, repo, pr.number, core);
return { ...result, prNumber: pr.number };
}
async function recoverStalledBotPrs(github, owner, repo, options, core) {
const { prNumber = null, minAgeMs = 10 * 60 * 1000, maxRecover = 10 } = options || {};
let prs;
if (prNumber) {
const { data } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
prs = [data];
} else if (typeof github.paginate === 'function') {
prs = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
});
} else {
const { data } = await github.rest.pulls.list({ owner, repo, state: 'open', per_page: 100 });
prs = data;
}
const cutoff = Date.now() - minAgeMs;
let recovered = 0;
for (const pr of prs) {
if (recovered >= maxRecover) break;
if (!isBotOpenedPr(pr)) continue;
if (!prNumber && new Date(pr.created_at).getTime() > cutoff) continue;
const comments = await listAllComments(github, owner, repo, pr.number);
if (chainKickPosted(comments)) continue;
await kickReviewChain(github, owner, repo, pr.number, core, comments);
recovered += 1;
}
core?.info?.(`Recovery complete (${recovered} PR(s) kicked)`);
return recovered;
}
module.exports = {
KICK_AUTHORS,
BOT_PR_AUTHORS,
listAllComments,
chainKickPosted,
coderabbitKickPosted,
qodoKickPosted,
isBotOpenedPr,
kickReviewChain,
findOpenPrForIssue,
kickReviewChainForIssue,
recoverStalledBotPrs,
};
@@ -0,0 +1,44 @@
#!/usr/bin/env node
/**
* Run: node .github/scripts/ci-failure-claude-selftest.js
*/
const ciFix = require('./ci-failure-claude.js');
const mergeGate = require('./merge-gate.js');
const config = require('./gate-config.js');
let failed = 0;
function assert(name, cond) {
if (!cond) {
console.error('FAIL:', name);
failed += 1;
} else {
console.log('ok:', name);
}
}
const LOG = `
python UNKNOWN STEP FAILED (0.0100s) tests/unit/test_example.py::test_foo - AssertionError: bar
python UNKNOWN STEP ##[error]Process completed with exit code 1.
`;
const parsed = ciFix.parsePytestFailures(LOG);
assert('parses pytest failure', parsed.length === 1);
assert('uses CI workflow list', config.ciFailureWorkflowRuns.includes('CI'));
const comment = ciFix.buildCiFixComment({
headSha: 'abc1234567890abcdef1234567890abcdef12',
failedChecks: [{ name: 'python', workflow: 'CI', html_url: 'https://example.com/job/1' }],
failureSummaries: [{ jobName: 'python', failures: parsed }],
});
assert('comment mentions product guardrails', comment.includes('Product guardrails'));
const skip = ciFix.shouldSkipCiFix({
comments: [],
headSha: 'abc1234567890abcdef1234567890abcdef12',
labels: [],
claudeInProgress: false,
failedChecks: [{ name: 'python', workflow: 'CI' }],
});
assert('ci fix without FINAL review allowed', !skip.skip);
process.exit(failed ? 1 : 0);
+293
View File
@@ -0,0 +1,293 @@
/**
* Post @claude comments with CI failure details for internal PRs.
* @see .github/workflows/ci-failure-claude.yml
*/
const mergeGate = require('./merge-gate.js');
const config = require('./gate-config.js');
const CI_FIX_LABEL = 'claude-ci-fix-pending';
const COOLDOWN_MS = 12 * 60 * 60 * 1000;
const AUTO_ACTORS = mergeGate.AUTO_ACTORS;
const MAX_FAILURES = 15;
const MAX_JOBS_TO_FETCH = 5;
function shortSha(headSha) {
return (headSha || '').slice(0, 8);
}
function ciFixShaMarker(headSha) {
return `ci failed on head \`${shortSha(headSha)}`.toLowerCase();
}
function isCiFixComment(comment) {
const body = (comment.body || '').toLowerCase();
return body.includes('@claude') && body.includes('ci failed on head');
}
function hasCiFixCommentForSha(comments, headSha) {
const marker = shortSha(headSha).toLowerCase();
return comments.some((c) => {
if (!AUTO_ACTORS.includes(c.user.login)) return false;
if (!isCiFixComment(c)) return false;
return (c.body || '').toLowerCase().includes(marker);
});
}
function hasRecentCiFixComment(comments, headSha) {
const cutoff = Date.now() - COOLDOWN_MS;
const marker = shortSha(headSha).toLowerCase();
return comments.some((c) => {
if (!AUTO_ACTORS.includes(c.user.login)) return false;
if (!isCiFixComment(c)) return false;
const body = (c.body || '').toLowerCase();
if (body.includes(marker)) return true;
return new Date(c.created_at).getTime() > cutoff;
});
}
function shouldSkipCiFix({ comments, headSha, labels, claudeInProgress, failedChecks }) {
if (!failedChecks.length) return { skip: true, reason: 'no failed checks' };
if (labels.includes(CI_FIX_LABEL)) return { skip: true, reason: 'ci fix pending' };
if (claudeInProgress) return { skip: true, reason: 'claude in progress' };
if (hasCiFixCommentForSha(comments, headSha)) {
return { skip: true, reason: 'already commented for this sha' };
}
if (hasRecentCiFixComment(comments, headSha)) {
return { skip: true, reason: 'recent ci fix comment cooldown' };
}
return { skip: false };
}
function parsePytestFailures(logText) {
if (!logText) return [];
const lines = logText.split('\n');
const failures = [];
const seen = new Set();
for (let i = lines.length - 1; i >= 0 && failures.length < MAX_FAILURES; i -= 1) {
const line = lines[i].trim();
if (!line) continue;
const pytestMatch = line.match(
/FAILED\s*(?:\([^)]+\))?\s+(tests\/[^\s]+(?:::[^\s-]+)*)\s*-\s*(.+)/i
);
if (pytestMatch) {
const testId = pytestMatch[1];
if (!seen.has(testId)) {
seen.add(testId);
failures.push({ testId, error: pytestMatch[2].trim() });
}
continue;
}
const errorMatch = line.match(/##\[error\](.+)/);
if (errorMatch && /tests\//.test(errorMatch[1])) {
const msg = errorMatch[1].trim();
if (!seen.has(msg)) {
seen.add(msg);
failures.push({ testId: msg, error: msg });
}
}
}
return failures;
}
async function fetchJobFailureSummary(github, owner, repo, jobId, jobName) {
try {
const response = await github.rest.actions.downloadJobLogsForWorkflowRun({
owner,
repo,
job_id: jobId,
});
let logText = typeof response.data === 'string' ? response.data : String(response.data || '');
if (logText.length > 100000) {
logText = logText.slice(-100000);
}
return { jobName, jobId, failures: parsePytestFailures(logText) };
} catch (err) {
return { jobName, jobId, failures: [], error: err.message };
}
}
function mapFailedChecks(runs) {
return runs.map((run) => ({
name: run.name,
id: run.id,
html_url: run.html_url || run.details_url,
workflow: run.app?.slug || run.check_suite?.app?.slug || run.name,
}));
}
function buildCiFixComment({ headSha, failedChecks, failureSummaries }) {
const parts = [
`@claude CI failed on HEAD \`${shortSha(headSha)}\`. Please fix the failures below and push to this branch.`,
'',
'## Failed checks',
];
for (const check of failedChecks) {
parts.push(`- **${check.workflow || check.name}** / \`${check.name}\` — ${check.html_url}`);
}
parts.push('', '## Failures (extracted)');
let idx = 0;
for (const summary of failureSummaries) {
for (const failure of summary.failures) {
idx += 1;
if (idx > MAX_FAILURES) break;
parts.push(`${idx}. \`${failure.testId}\` — \`${failure.error}\``);
parts.push(` - Job: \`${summary.jobName}\``);
}
if (idx >= MAX_FAILURES) break;
}
if (idx === 0) {
parts.push('_(Could not extract pytest details — see job logs above.)_');
}
const exampleTest = failureSummaries.find((s) => s.failures.length)?.failures[0]?.testId;
parts.push(
'',
'## Critical review first',
'Before changing code or tests, decide **which side is wrong**:',
'1. **Legitimate feature change** — the PR intent is correct but implementation or tests need updating. Preserve product guarantees; update tests only when behaviour intentionally changed and document why.',
'2. **Regression / bug in this PR** — the failure exposes a real breakage introduced here. Fix the implementation; **do not weaken, skip, or delete tests** just to go green.',
'3. **Pre-existing flake or unrelated failure** — say so explicitly; prefer fixing the root cause over masking it.',
'',
'**Product guardrails (AGENTS.md):**',
'- Do not disturb PraisonAIUI contracts or frontend/backend layering to accommodate scope creep.',
'- Core agent runtime belongs in praisonaiagents; agent-callable tools belong in PraisonAI-Tools — not here.',
'- Prefer existing YAML config, plugins, and feature modules over new server.py/create_app() params or knobs with no live consumer.',
'- Tests must continue to guard backward compatibility and UX behaviour — passing CI by lowering test standards is not acceptable.',
'- If the feature does not genuinely add product value, recommend reverting or narrowing scope instead of patching around failures.',
'',
'## What to do',
'1. State your verdict: **legitimate fix**, **regression fix**, or **needs human review** — and why (1–3 sentences).',
'2. Fix root cause with **minimal changes**; never bloat server.py or create_app() with extra params.',
exampleTest
? `3. Run failing tests locally, e.g. \`pytest ${exampleTest} -q\`, plus any related tests touched by the PR.`
: '3. Run failing tests locally with targeted pytest, plus any related tests touched by the PR.',
'4. Push to this branch and comment: files changed, review verdict, and why tests still protect product behaviour.',
);
return parts.join('\n');
}
async function maybeClearCiFixLabel(github, owner, repo, prNumber, labels, headSha, core) {
if (!labels.includes(CI_FIX_LABEL)) return false;
const ciGreen = await mergeGate.allChecksGreenOnSha(github, owner, repo, headSha, core);
if (!ciGreen) return false;
try {
await github.rest.issues.removeLabel({
owner,
repo,
issue_number: prNumber,
name: CI_FIX_LABEL,
});
core?.info?.(`Removed ${CI_FIX_LABEL} from PR #${prNumber}`);
} catch (err) {
if (err.status !== 404) throw err;
}
return true;
}
async function maybeTriggerCiFixClaude(github, owner, repo, prNumber, core, opts = {}) {
const baseRepo = `${owner}/${repo}`;
const ctx = await mergeGate.loadPrContext(github, owner, repo, prNumber);
const pr = ctx.pr;
if (pr.state !== 'open') return { skipped: true, reason: 'not open' };
if (pr.draft) return { skipped: true, reason: 'draft' };
const headRepo = pr.head.repo?.full_name;
if (headRepo && headRepo !== baseRepo && !pr.maintainer_can_modify) {
return { skipped: true, reason: 'fork without maintainer edits' };
}
const headSha = pr.head.sha;
const labels = ctx.labels;
if (await maybeClearCiFixLabel(github, owner, repo, prNumber, labels, headSha, core)) {
return { skipped: true, reason: 'ci green, label cleared' };
}
const ciGreen = await mergeGate.allChecksGreenOnSha(github, owner, repo, headSha, core);
if (ciGreen) return { skipped: true, reason: 'ci green' };
const runs = await mergeGate.listChecksOnSha(github, owner, repo, headSha);
const failedRuns = mergeGate.listFailedChecksOnSha(runs);
if (failedRuns.length === 0) {
return { skipped: true, reason: 'no failed checks yet (may be pending)' };
}
const claudeInProgress = await mergeGate.hasInProgressClaudeAssistant(
github, owner, repo, prNumber
);
const skip = shouldSkipCiFix({
comments: ctx.comments,
headSha,
labels,
claudeInProgress,
failedChecks: failedRuns,
});
if (skip.skip) return { skipped: true, reason: skip.reason };
const failedChecks = mapFailedChecks(failedRuns);
const failureSummaries = [];
for (const check of failedChecks.slice(0, MAX_JOBS_TO_FETCH)) {
failureSummaries.push(
await fetchJobFailureSummary(github, owner, repo, check.id, check.name)
);
}
const body = buildCiFixComment({ headSha, failedChecks, failureSummaries });
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: [CI_FIX_LABEL],
});
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body,
});
core?.info?.(`Posted CI fix @claude on PR #${prNumber} (${shortSha(headSha)})`);
return { triggered: true, headSha: shortSha(headSha) };
}
async function processWorkflowRunFailure(github, owner, repo, workflowRun, core) {
if (workflowRun.conclusion !== 'failure') {
return { skipped: true, reason: `conclusion=${workflowRun.conclusion}` };
}
const allowed = config.ciFailureWorkflowRuns;
if (!allowed.includes(workflowRun.name)) {
return { skipped: true, reason: `workflow ${workflowRun.name}` };
}
const prNumber = await mergeGate.resolvePrNumberFromWorkflowRun(
github, owner, repo, workflowRun
);
if (!prNumber) return { skipped: true, reason: 'no linked PR' };
return maybeTriggerCiFixClaude(github, owner, repo, prNumber, core);
}
module.exports = {
CI_FIX_LABEL,
COOLDOWN_MS,
ciFixShaMarker,
isCiFixComment,
hasCiFixCommentForSha,
hasRecentCiFixComment,
shouldSkipCiFix,
parsePytestFailures,
fetchJobFailureSummary,
buildCiFixComment,
maybeClearCiFixLabel,
maybeTriggerCiFixClaude,
processWorkflowRunFailure,
};
+55
View File
@@ -0,0 +1,55 @@
/**
* PraisonAIUI gate configuration — imported by merge-gate, release-gate, ci-failure-claude.
*/
module.exports = {
repoFullName: 'MervinPraison/PraisonAIUI',
gitUser: 'MervinPraison',
gitEmail: '[email protected]',
triggerLogins: ['MervinPraison', 'github-actions[bot]'],
allowedTriageBots: ['praisonai-triage-agent[bot]'],
productPathPrefixes: ['src/praisonaiui/', 'src/frontend/', 'tests/'],
sensitivePathPatterns: [
/^\.github\/workflows\//,
/^pyproject\.toml$/,
/credentials\.json$/i,
],
requiredCheckPatterns: [/^ci$/i, /python/i, /test/i, /lint/i, /ruff/i],
ciWorkflowFile: 'ci.yml',
ciWorkflowName: 'CI',
mergeGateWorkflowRuns: ['CI', 'Claude Assistant'],
ciFailureWorkflowRuns: ['CI'],
pypiPackageName: 'aiui',
packagePaths: ['src/praisonaiui', 'src/frontend', 'pyproject.toml'],
finalClaudeScope:
'SCOPE: Focus ONLY on PraisonAIUI (src/praisonaiui, src/frontend, tests, docs). '
+ 'Do NOT expand into praisonaiagents or the monorepo unless the PR explicitly requires it.',
finalClaudeProductValue:
'4. Product value: review in depth whether the change genuinely adds PraisonAIUI UX value — '
+ 'never add features for the sake of adding them. It must strengthen the UI (simpler, '
+ 'more user-friendly, robust). If it does not clearly add value, request changes or recommend '
+ 'rejecting/closing rather than merging scope creep.\n'
+ '5. Layering: UI/frontend/server features here; core agent runtime belongs in praisonaiagents '
+ '(PraisonAI monorepo). Agent-callable tools → PraisonAI-Tools. Do not pull monorepo or SDK '
+ 'scope into this repo unless the PR explicitly requires it.\n'
+ '6. Do not bloat server.py or create_app() with new params — prefer existing YAML config, '
+ 'plugins, and feature modules; only add params if absolutely required. Reject knobs/exports '
+ 'with no live consumer.',
mergeGateProductValue:
'Confirm product value gate: change strengthens PraisonAIUI UX (no scope creep). The aim is a '
+ 'LIGHTWEIGHT AND POWERFUL package — BLOCK changes that add params/modules/exports duplicating '
+ 'existing UI capabilities (YAML config, plugins, feature modules, existing server hooks), or '
+ 'add knobs/fields with no live consumer, i.e. scope creep for the sake of it.',
mergeGateLayering:
'Layering routing: BLOCK if core agent logic was added here instead of praisonaiagents; BLOCK if '
+ 'agent-callable tools were added here instead of PraisonAI-Tools.',
mergeGateServerBloat:
'Do not bloat server.py or create_app() with additional params — only if absolutely required; '
+ 'prefer existing config/plugin patterns.',
agentPyChecks: false,
reviewBotLogins: [
'coderabbitai[bot]',
'qodo-code-review[bot]',
'greptile-apps[bot]',
],
};
+234
View File
@@ -0,0 +1,234 @@
#!/usr/bin/env node
/**
* Local self-test for merge-gate.js heuristics (no GitHub API).
* Run: node .github/scripts/merge-gate-selftest.js
*/
const mg = require('./merge-gate.js');
let failed = 0;
function assert(name, cond) {
if (!cond) {
console.error('FAIL:', name);
failed++;
} else {
console.log('ok:', name);
}
}
// Stale FINAL: push after FINAL, no @claude since head
const finals = [
{ user: { login: 'github-actions[bot]' }, body: '@claude FINAL architecture reviewer', created_at: '2026-06-12T08:00:00Z' },
];
assert('stale when head after final', mg.isStaleFinalAfterPush(finals, '2026-06-12T09:00:00Z'));
const withRecovery = [
...finals,
{ user: { login: 'github-actions[bot]' }, body: '@claude FINAL architecture reviewer', created_at: '2026-06-12T09:30:00Z' },
];
assert('not stale when @claude after head', !mg.isStaleFinalAfterPush(withRecovery, '2026-06-12T09:00:00Z'));
const withClaudeReply = [
...finals,
{
user: { login: 'praisonai-triage-agent[bot]' },
body: "**Claude finished @MervinPraison's task** —— [View job](https://github.com/)",
created_at: '2026-06-12T08:30:00Z',
},
];
assert('not stale when Claude replied after FINAL', !mg.isStaleFinalAfterPush(withClaudeReply, '2026-06-12T09:00:00Z'));
assert('claude final reply detected', mg.isClaudeFinalReplyComment(withClaudeReply[1]));
assert('cancelled detect-and-trigger does not block', mg.OPTIONAL_CANCELLED_CHECKS.has('detect-and-trigger'));
// Stale-FINAL recovery guards (PR #2560 push loop)
const nowMs = Date.now();
const iso = (ms) => new Date(ms).toISOString();
const firstFinal = {
user: { login: 'MervinPraison' },
body: '@claude You are the FINAL architecture reviewer.',
created_at: iso(nowMs - 20 * 60 * 1000),
};
const pushSoonAfter = mg.shouldSkipStaleFinalRecovery(
[firstFinal],
iso(nowMs - 16 * 60 * 1000)
);
assert('debounce push soon after FINAL', pushSoonAfter.skip && pushSoonAfter.reason.includes('soon after'));
const secondFinal = {
user: { login: 'MervinPraison' },
body: '@claude You are the FINAL architecture reviewer.',
created_at: iso(nowMs - 20 * 60 * 1000),
};
const capped = mg.shouldSkipStaleFinalRecovery(
[firstFinal, secondFinal],
iso(nowMs - 2 * 60 * 1000)
);
assert('hourly cap blocks third FINAL in window', capped.skip && capped.reason.includes('capped'));
const botPush = mg.shouldSkipStaleFinalRecovery(
[firstFinal],
iso(nowMs - 16 * 60 * 1000),
'praisonai-triage-agent[bot]'
);
assert('skip when automation pushed head', botPush.skip && botPush.reason.includes('automation'));
assert('claude automation login', mg.isClaudeAutomationLogin('praisonai-triage-agent[bot]'));
// Bot CHANGES_REQUESTED then APPROVE
const reviews = [
{ user: { login: 'coderabbit[bot]', type: 'Bot' }, state: 'CHANGES_REQUESTED', submitted_at: '2026-06-12T08:00:00Z' },
{ user: { login: 'coderabbit[bot]', type: 'Bot' }, state: 'APPROVED', submitted_at: '2026-06-12T09:00:00Z' },
];
assert('bot approve clears CR', !mg.hasAnyChangesRequested(reviews));
assert('human CR blocks', mg.hasAnyChangesRequested([
{ user: { login: 'MervinPraison', type: 'User' }, state: 'CHANGES_REQUESTED', submitted_at: '2026-06-12T09:00:00Z' },
]));
// Verdict after HEAD
const verdictComments = [
{ body: 'MERGE_GATE_VERDICT: APPROVE', created_at: '2026-06-12T08:00:00Z' },
];
assert('verdict before head rejected', mg.findMergeGateVerdict(verdictComments, null, '2026-06-12T09:00:00Z') === null);
assert('verdict after head accepted', mg.findMergeGateVerdict(
[{ body: 'MERGE_GATE_VERDICT: APPROVE', created_at: '2026-06-12T10:00:00Z' }],
null,
'2026-06-12T09:00:00Z'
) === 'APPROVE');
const fallbackApprove = [
{
body: 'MERGE_GATE_VERDICT: APPROVE\n\nAutomated fallback — Claude assess did not post a verdict comment.',
created_at: '2026-06-12T10:00:00Z',
},
];
assert(
'automated fallback APPROVE ignored when Opus required',
mg.findMergeGateVerdict(fallbackApprove, null, '2026-06-12T09:00:00Z', { excludeAutomatedFallback: true }) === null
);
assert(
'automated fallback APPROVE still visible without Opus-only filter',
mg.findMergeGateVerdict(fallbackApprove, null, '2026-06-12T09:00:00Z') === 'APPROVE'
);
const fallbackBlockNewFormat = [
{
body: 'MERGE_GATE_VERDICT: BLOCK\n\nAutomated fallback — Opus merge gate assessment did not complete.',
created_at: '2026-06-12T10:00:00Z',
},
];
assert(
'new-format fallback BLOCK ignored when Opus required',
mg.findMergeGateVerdict(fallbackBlockNewFormat, null, '2026-06-12T09:00:00Z', { excludeAutomatedFallback: true }) === null
);
assert(
'new-format fallback BLOCK detected by marker helper',
mg.isAutomatedFallbackVerdict(fallbackBlockNewFormat[0].body)
);
assert(
'findMergeGateVerdict null-safe with explicit null options',
mg.findMergeGateVerdict(fallbackApprove, null, '2026-06-12T09:00:00Z', null) === 'APPROVE'
);
const noise = [{ user: { login: 'MervinPraison' }, body: '**Merge gate scan** — wait for `@claude`', created_at: new Date().toISOString() }];
assert('diagnostic comment not a trigger', !mg.hasRecentClaudeTrigger(noise, 35));
// Cooldown skip requires an actual verdict on HEAD, not just a FINAL trigger comment
const recentFinalOnHead = [
{
user: { login: 'MervinPraison' },
body: '@claude You are the FINAL architecture reviewer.',
created_at: '2026-06-27T10:00:00Z',
},
];
assert(
'final trigger alone does not count as verdict on head',
mg.findMergeGateVerdict(recentFinalOnHead, null, '2026-06-27T09:55:00Z') === null
);
const recentVerdictOnHead = [
...recentFinalOnHead,
{
user: { login: 'github-actions[bot]' },
body: 'MERGE_GATE_VERDICT: APPROVE',
created_at: '2026-06-27T10:05:00Z',
},
];
assert(
'verdict on head skips cooldown gate',
mg.findMergeGateVerdict(recentVerdictOnHead, null, '2026-06-27T09:55:00Z') === 'APPROVE'
);
// Sensitive + secrets
assert('workflow path sensitive', mg.sensitivePathReasons([{ filename: '.github/workflows/foo.yml' }]).length === 1);
assert('ci-only label exempts workflows', mg.sensitivePathReasons(
[{ filename: '.github/workflows/foo.yml' }],
[mg.WORKFLOW_ONLY_LABEL]
).length === 0);
assert('ci-only label not exempt mixed changes', mg.sensitivePathReasons(
[{ filename: '.github/workflows/foo.yml' }, { filename: 'src/praisonaiui/foo.py' }],
[mg.WORKFLOW_ONLY_LABEL]
).length === 1);
assert('secret in patch', mg.secretScanReasons([{ filename: 'x.py', patch: '+key = "ghp_abcdefghijklmnopqrstuvwxyz1234567890"' }]).length === 1);
// Claude run scoping — other PR branches must not block
assert('other branch claude does not block', !mg.hasBlockingClaudeRunForPr(
[{ event: 'issue_comment', head_branch: 'other-branch' }],
'my-branch'
));
assert('same branch claude blocks', mg.hasBlockingClaudeRunForPr(
[{ event: 'issue_comment', head_branch: 'my-branch' }],
'my-branch'
));
assert('issues event never blocks', !mg.hasBlockingClaudeRunForPr(
[{ event: 'issues', head_branch: 'my-branch' }],
'my-branch'
));
// Conflict rebase clears after bot completion + FINAL on HEAD (within 12h cooldown)
const conflictNowMs = Date.now();
const conflictIso = (offsetMs) => new Date(conflictNowMs + offsetMs).toISOString();
const conflictTrigger = {
user: { login: 'MervinPraison' },
body: '@claude this PR has merge conflicts with main. Please rebase',
created_at: conflictIso(-30 * 60 * 1000),
};
const rebaseDone = {
user: { login: 'praisonai-triage-agent[bot]' },
body: 'Rebase complete — PR #2308 onto latest main',
created_at: conflictIso(-29 * 60 * 1000),
};
const finalAfterRebase = {
user: { login: 'MervinPraison' },
body: '@claude You are the FINAL architecture reviewer.',
created_at: conflictIso(-20 * 60 * 1000),
};
const headAfterRebase = conflictIso(-21 * 60 * 1000);
const rebaseComments = [conflictTrigger, rebaseDone, finalAfterRebase];
assert('conflict blocks before rebase done', mg.hasRecentConflictComment([conflictTrigger], headAfterRebase));
assert('conflict clears after rebase + FINAL on HEAD', !mg.hasRecentConflictComment(rebaseComments, headAfterRebase));
assert('conflict clears after rebase without FINAL on HEAD', !mg.hasRecentConflictComment(
[conflictTrigger, rebaseDone],
headAfterRebase
));
// Tests heuristic
assert('product code without tests', mg.missingTestsReason([{ filename: 'src/praisonaiui/a/b.py', additions: 3 }]) !== null);
assert('product code with tests ok', mg.missingTestsReason([
{ filename: 'src/praisonaiui/a/b.py', additions: 3 },
{ filename: 'tests/test_x.py', additions: 10 },
]) === null);
// PR size
assert('large PR blocked', mg.prSizeReasons([{ additions: 900 }]).length > 0);
assert('internal PR link accepted', mg.isInternalPullRequestLink(
{ base: { repo: { full_name: 'MervinPraison/PraisonAIUI' } } },
'MervinPraison',
'PraisonAIUI'
));
assert('fork sync PR link rejected', !mg.isInternalPullRequestLink(
{ number: 21, base: { repo: { full_name: 'Milkmange/PraisonAIUI' } } },
'MervinPraison',
'PraisonAIUI'
));
process.exit(failed ? 1 : 0);
+940
View File
@@ -0,0 +1,940 @@
/**
* Shared merge-gate helpers for claude-merge-gate.yml
* @see .github/workflows/claude-merge-gate.yml
*/
const config = require('./gate-config.js');
const CLAUDE_TRIGGER_LOGINS = ['MervinPraison', 'github-actions[bot]'];
const AUTO_ACTORS = CLAUDE_TRIGGER_LOGINS;
const CONFLICT_COOLDOWN_MS = 12 * 60 * 60 * 1000;
const CLAUDE_ACTIVE_MS = 35 * 60 * 1000;
const STALE_FINAL_RECOVERY_WINDOW_MS = 60 * 60 * 1000;
const STALE_FINAL_MAX_PER_WINDOW = 2;
const PUSH_AFTER_FINAL_DEBOUNCE_MS = 15 * 60 * 1000;
const ALLOWED_MERGE_STATES = new Set(['CLEAN', 'UNSTABLE']);
const AGENT_PY_MAX_AUTO_LINES = 100;
const PR_MAX_AUTO_ADDITIONS = 800;
const PR_MAX_AUTO_FILES = 30;
const MANUAL_ONLY_LABELS = new Set(['security', 'breaking-change', 'needs-manual-review', 'release']);
const WORKFLOW_ONLY_LABEL = 'merge-gate-ci-only';
const CI_ONLY_PATH_PREFIXES = ['.github/workflows/', '.github/actions/', '.github/scripts/merge-gate'];
const SDK_PATH_PREFIXES = config.productPathPrefixes;
const SENSITIVE_PATH_PATTERNS = config.sensitivePathPatterns;
const REQUIRED_SDK_CHECK_PATTERNS = config.requiredCheckPatterns;
const SECRET_PATTERNS = [
/sk-[a-zA-Z0-9]{20,}/,
/AKIA[0-9A-Z]{16}/,
/ghp_[a-zA-Z0-9]{36,}/,
/github_pat_/,
/Bearer eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/,
/-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----/,
];
const BLOCK_LABELS = new Set([
'claude-conflict-pending',
'claude-merge-gate-active',
'no-auto-merge',
'auto-merged-by-gate',
]);
const MERGE_READY_LABEL = 'pipeline/merge-ready';
/** Superseded concurrency runs; must not block merge when real tests passed. */
const OPTIONAL_CANCELLED_CHECKS = new Set(['detect-and-trigger']);
const BOT_REVIEWER_PATTERNS = [
'coderabbit',
'qodo',
'gemini',
'copilot',
'greptile',
];
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
function isFinalClaudeTriggerComment(c) {
const body = (c.body || '').toLowerCase();
if (!AUTO_ACTORS.includes(c.user.login)) return false;
if (!body.includes('@claude')) return false;
if (body.includes('merge conflict')) return false;
return body.includes('final architecture reviewer') || body.includes('lead engineer');
}
function isClaudeTriggerNoise(c) {
const body = c.body || '';
if (body.includes('Merge gate scan')) return true;
if (body.includes('MERGE_GATE_VERDICT')) return true;
if (body.includes('Merged by **Claude PR merge gate**')) return true;
return false;
}
function isClaudeFinalReplyComment(c) {
const login = (c.user?.login || '').toLowerCase();
const fromAutomation =
login.includes('praisonai-triage') ||
login.includes('github-actions') ||
AUTO_ACTORS.some((a) => a.toLowerCase() === login);
if (!fromAutomation) return false;
return (c.body || '').includes('Claude finished');
}
function hasRecentClaudeTrigger(comments, minutes = 35) {
const cutoff = Date.now() - minutes * 60 * 1000;
return comments.some((c) => {
if (!CLAUDE_TRIGGER_LOGINS.includes(c.user.login)) return false;
if (isClaudeTriggerNoise(c)) return false;
if (!(c.body || '').includes('@claude')) return false;
return new Date(c.created_at).getTime() > cutoff;
});
}
function isConflictRebaseTriggerComment(c) {
if (!AUTO_ACTORS.includes(c.user.login)) return false;
const body = (c.body || '').toLowerCase();
return body.includes('@claude') && body.includes('merge conflict');
}
function isConflictRebaseCompletionComment(c) {
const login = (c.user?.login || '').toLowerCase();
const fromAutomation =
login.includes('praisonai-triage') ||
login.includes('github-actions') ||
AUTO_ACTORS.some((a) => a.toLowerCase() === login);
if (!fromAutomation) return false;
const body = (c.body || '').toLowerCase();
return (
body.includes('rebase complete') ||
body.includes('rebase onto') ||
body.includes('force-pushed') ||
(body.includes('conflict') && body.includes('resolved'))
);
}
/** HEAD landed after conflict rebase but no FINAL @claude since that push. */
function needsFinalReReviewAfterConflictRebase(comments, headPushedAt) {
if (!headPushedAt) return false;
const headTime = new Date(headPushedAt).getTime();
const conflictTriggers = comments.filter(isConflictRebaseTriggerComment);
if (conflictTriggers.length === 0) return false;
const latestConflict = conflictTriggers.reduce((a, b) =>
new Date(a.created_at) > new Date(b.created_at) ? a : b
);
const conflictTime = new Date(latestConflict.created_at).getTime();
if (headTime <= conflictTime) return false;
const rebaseDone = comments.some(
(c) =>
new Date(c.created_at).getTime() > conflictTime && isConflictRebaseCompletionComment(c)
);
if (!rebaseDone) return false;
const finalsAfterHead = comments.filter(
(c) =>
isFinalClaudeTriggerComment(c) &&
new Date(c.created_at).getTime() >= headTime - 60000
);
return finalsAfterHead.length === 0;
}
function conflictRebaseQuiescent(comments, headPushedAt) {
const conflictTriggers = comments.filter(isConflictRebaseTriggerComment);
if (conflictTriggers.length === 0) return true;
const latestConflict = conflictTriggers.reduce((a, b) =>
new Date(a.created_at) > new Date(b.created_at) ? a : b
);
const conflictTime = new Date(latestConflict.created_at).getTime();
const rebaseDone = comments.some(
(c) =>
new Date(c.created_at).getTime() > conflictTime && isConflictRebaseCompletionComment(c)
);
if (!rebaseDone) return false;
return true;
}
function hasRecentConflictComment(comments, headPushedAt = null) {
const cutoff = Date.now() - CONFLICT_COOLDOWN_MS;
const hasRecentTrigger = comments.some((c) => {
if (!isConflictRebaseTriggerComment(c)) return false;
return new Date(c.created_at).getTime() > cutoff;
});
if (!hasRecentTrigger) return false;
if (headPushedAt && conflictRebaseQuiescent(comments, headPushedAt)) {
return false;
}
return true;
}
function isBotReviewer(login, userType) {
const lower = (login || '').toLowerCase();
if (userType === 'Bot') return true;
if (lower.endsWith('[bot]')) return true;
return ['coderabbit', 'qodo', 'gemini', 'copilot', 'greptile'].some((p) => lower.includes(p));
}
function latestReviewsByUser(reviews) {
const latestByUser = new Map();
for (const r of reviews) {
const login = r.user?.login;
if (!login) continue;
const prev = latestByUser.get(login);
if (!prev || new Date(r.submitted_at) > new Date(prev.submitted_at)) {
latestByUser.set(login, r);
}
}
return latestByUser;
}
function hasHumanChangesRequested(reviews) {
for (const [login, review] of latestReviewsByUser(reviews)) {
if (review.state !== 'CHANGES_REQUESTED') continue;
if (!isBotReviewer(login, review.user?.type)) return true;
}
return false;
}
function hasAnyChangesRequested(reviews) {
for (const [, review] of latestReviewsByUser(reviews)) {
if (review.state === 'CHANGES_REQUESTED') return true;
}
return false;
}
function hasFinalClaudeReviewTrigger(comments) {
return comments.some(isFinalClaudeTriggerComment);
}
function isStaleFinalAfterPush(comments, headPushedAt) {
if (!headPushedAt) return false;
const headTime = new Date(headPushedAt).getTime();
const finals = comments.filter(isFinalClaudeTriggerComment);
if (finals.length === 0) return true;
const latestFinal = finals.reduce((a, b) =>
new Date(a.created_at) > new Date(b.created_at) ? a : b
);
const finalTime = new Date(latestFinal.created_at).getTime();
if (headTime <= finalTime + 60000) return false;
const claudeRepliedAfterFinal = comments.some((c) => {
if (!isClaudeFinalReplyComment(c)) return false;
return new Date(c.created_at).getTime() >= finalTime - 60000;
});
if (claudeRepliedAfterFinal) return false;
const claudeSinceHead = comments.some((c) => {
if (!CLAUDE_TRIGGER_LOGINS.includes(c.user.login)) return false;
if (isClaudeTriggerNoise(c)) return false;
if (!(c.body || '').includes('@claude')) return false;
return new Date(c.created_at).getTime() >= headTime - 60000;
});
return !claudeSinceHead;
}
function needsStaleFinalRecovery(comments, headPushedAt) {
return (
hasFinalClaudeReviewTrigger(comments) &&
isStaleFinalAfterPush(comments, headPushedAt)
);
}
function shouldSkipFinalRecovery(comments, headPushedAt) {
const isStale = isStaleFinalAfterPush(comments, headPushedAt);
if (isStale) return false;
return hasRecentClaudeTrigger(comments, 35);
}
function countFinalTriggersSince(comments, sinceMs) {
return comments.filter(
(c) => isFinalClaudeTriggerComment(c) && new Date(c.created_at).getTime() > sinceMs
).length;
}
function isClaudeAutomationLogin(login) {
const lower = (login || '').toLowerCase();
return lower.includes('praisonai-triage') || lower === 'github-actions[bot]';
}
function isPushSoonAfterLatestFinal(comments, headPushedAt) {
if (!headPushedAt) return false;
const finals = comments.filter(isFinalClaudeTriggerComment);
if (finals.length === 0) return false;
const latestFinal = finals.reduce((a, b) =>
new Date(a.created_at) > new Date(b.created_at) ? a : b
);
const finalTime = new Date(latestFinal.created_at).getTime();
const headTime = new Date(headPushedAt).getTime();
if (headTime <= finalTime) return false;
return headTime - finalTime < PUSH_AFTER_FINAL_DEBOUNCE_MS;
}
/** Returns { skip: true, reason } when stale-FINAL recovery should not post. */
function shouldSkipStaleFinalRecovery(comments, headPushedAt, headPusherLogin = null) {
if (!isStaleFinalAfterPush(comments, headPushedAt)) {
return { skip: true, reason: 'not stale' };
}
if (headPusherLogin && isClaudeAutomationLogin(headPusherLogin)) {
return { skip: true, reason: 'head pushed by Claude automation' };
}
if (needsFinalReReviewAfterConflictRebase(comments, headPushedAt)) {
return { skip: false, reason: '' };
}
if (isPushSoonAfterLatestFinal(comments, headPushedAt)) {
return {
skip: true,
reason: 'head pushed soon after FINAL (wait for CI / batched fixes)',
};
}
const windowStart = Date.now() - STALE_FINAL_RECOVERY_WINDOW_MS;
const finalsInWindow = countFinalTriggersSince(comments, windowStart);
if (finalsInWindow >= STALE_FINAL_MAX_PER_WINDOW) {
return {
skip: true,
reason: `stale-FINAL capped (${finalsInWindow} FINAL triggers in last hour)`,
};
}
return { skip: false, reason: '' };
}
function finalClaudeCompletedOnSha(comments, headPushedAt) {
if (!hasFinalClaudeReviewTrigger(comments)) return false;
if (isStaleFinalAfterPush(comments, headPushedAt)) return false;
return true;
}
const FINAL_CLAUDE_REVIEW_BODY =
`@claude You are the FINAL architecture reviewer. If the branch is under ${config.repoFullName} (not a fork), you are able to make modifications to this branch and push directly. ${config.finalClaudeScope} Read ALL comments above from Gemini, Qodo, CodeRabbit, and Copilot carefully before responding.\n\n**Phase 1: Review per AGENTS.md**\n1. Protocol-driven: check heavy implementations vs core SDK\n2. Backward compatible: ensure zero feature regressions\n3. Performance: no hot-path regressions (lazy imports, import-time <200ms)\n${config.finalClaudeProductValue}\n\n**Phase 2: FIX Valid Issues**\n5. For any VALID bugs or architectural flaws found by Gemini, CodeRabbit, Qodo, Copilot, or any other reviewer: implement the fix\n6. Push all code fixes directly to THIS branch (do NOT create a new PR)\n7. Comment a summary of exact files modified and what you skipped\n\n**Phase 3: Final Verdict**\n8. If all issues are resolved, approve the PR / close the Issue\n9. If blocking issues remain, request changes / leave clear action items`;
async function getMergeState(github, owner, repo, prNumber) {
const query = `
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
mergeStateStatus
maintainerCanModify
isDraft
headRefOid
headRef { repository { nameWithOwner } }
}
}
}
`;
for (let attempt = 0; attempt < 3; attempt++) {
const result = await github.graphql(query, { owner, repo, number: prNumber });
const prGql = result.repository.pullRequest;
const status = (prGql?.mergeStateStatus || '').toUpperCase();
if (status && status !== 'UNKNOWN') {
return {
status,
isDraft: prGql.isDraft,
headRepo: prGql.headRef?.repository?.nameWithOwner,
headSha: prGql.headRefOid,
maintainerCanModify: prGql.maintainerCanModify === true,
};
}
if (attempt < 2) await sleep(10000);
}
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
return {
status: (pr.mergeable_state || '').toUpperCase(),
isDraft: pr.draft,
headRepo: pr.head.repo?.full_name,
headSha: pr.head.sha,
maintainerCanModify: pr.maintainer_can_modify === true,
};
}
async function listChecksOnSha(github, owner, repo, sha) {
const { data } = await github.rest.checks.listForRef({
owner,
repo,
ref: sha,
per_page: 100,
});
return (data.check_runs || []).filter((r) => r.head_sha === sha);
}
function listFailedChecksOnSha(runs) {
return (runs || []).filter((run) => {
if (run.status !== 'completed') return false;
return run.conclusion === 'failure';
});
}
async function allChecksGreenOnSha(github, owner, repo, sha, core) {
const runs = await listChecksOnSha(github, owner, repo, sha);
if (runs.length === 0) {
core?.info?.(`No check runs on ${sha.slice(0, 7)} — allowing (e.g. docs-only PR)`);
return true;
}
for (const run of runs) {
if (run.status !== 'completed') {
core?.info?.(`Check pending: ${run.name} (${run.status})`);
return false;
}
const ok =
['success', 'neutral', 'skipped'].includes(run.conclusion) ||
(run.conclusion === 'cancelled' && OPTIONAL_CANCELLED_CHECKS.has(run.name));
if (!ok) {
core?.info?.(`Check failed: ${run.name} (${run.conclusion})`);
return false;
}
}
return true;
}
function claudeRunBlocksPr(run, headRef) {
if (!run || run.event === 'issues') return false;
if (!headRef) return true;
return run.head_branch === headRef;
}
function hasBlockingClaudeRunForPr(runs, headRef) {
return (runs || []).some((r) => claudeRunBlocksPr(r, headRef));
}
async function hasInProgressClaudeAssistant(github, owner, repo, prNumber = null) {
try {
const { data } = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: 'claude.yml',
status: 'in_progress',
per_page: 20,
});
const runs = (data.workflow_runs || []).filter((r) => r.event !== 'issues');
if (runs.length === 0) return false;
if (prNumber == null) return runs.length > 0;
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
const headRef = pr.head.ref;
return hasBlockingClaudeRunForPr(runs, headRef);
} catch {
return false;
}
}
function isCiOnlyChange(files) {
if (!files.length) return false;
return files.every((f) => CI_ONLY_PATH_PREFIXES.some((p) => f.filename.startsWith(p)));
}
function isInternalPullRequestLink(link, owner, repo) {
if (link?.base?.repo?.full_name === `${owner}/${repo}`) return true;
const baseUrl = link?.base?.repo?.url || '';
return baseUrl.endsWith(`/repos/${owner}/${repo}`);
}
async function resolvePrNumberFromLinkedPullRequests(github, owner, repo, linked) {
const repoFull = `${owner}/${repo}`;
const internal = (linked || []).filter((l) => isInternalPullRequestLink(l, owner, repo));
for (const link of internal) {
if (!link.number) continue;
try {
const { data } = await github.rest.pulls.get({
owner,
repo,
pull_number: link.number,
});
if (data.state === 'open' && data.base?.repo?.full_name === repoFull) {
return data.number;
}
} catch (err) {
if (err.status !== 404) throw err;
}
}
return null;
}
async function resolvePrNumberFromHeadBranch(github, owner, repo, branch) {
if (!branch || branch === 'main' || branch === 'master') return null;
const { data } = await github.rest.pulls.list({
owner,
repo,
state: 'open',
head: `${owner}:${branch}`,
per_page: 1,
});
return data[0]?.number || null;
}
async function resolvePrNumberFromWorkflowRun(github, owner, repo, workflowRun) {
const fromLinked = await resolvePrNumberFromLinkedPullRequests(
github, owner, repo, workflowRun.pull_requests
);
if (fromLinked) return fromLinked;
const fromBranch = await resolvePrNumberFromHeadBranch(
github, owner, repo, workflowRun.head_branch
);
if (fromBranch) return fromBranch;
return null;
}
async function listPullFiles(github, owner, repo, prNumber) {
if (typeof github.paginate === 'function') {
return github.paginate(github.rest.pulls.listFiles, {
owner,
repo,
pull_number: prNumber,
per_page: 100,
});
}
const { data } = await github.rest.pulls.listFiles({
owner,
repo,
pull_number: prNumber,
per_page: 100,
});
return data;
}
function countNewAgentParams(patch) {
if (!patch) return 0;
return patch
.split('\n')
.filter((l) => l.startsWith('+') && !l.startsWith('+++'))
.filter((l) => {
const t = l.slice(1).trim();
if (!t || t.startsWith('#') || t.startsWith('"""') || t.startsWith("'''")) return false;
if (/^(def|class|@|return\b|if\b|elif\b|else\b|for\b|while\b)/.test(t)) return false;
if (/^\w+\s*[:=]/.test(t) && !t.startsWith('self.')) return true;
return false;
}).length;
}
function getAgentPyChangeFromFiles(files) {
const agentFile = files.find((f) => f.filename.endsWith('praisonaiagents/agent/agent.py'));
if (!agentFile) {
return { touched: false, additions: 0, newParams: 0 };
}
return {
touched: true,
additions: agentFile.additions || 0,
newParams: countNewAgentParams(agentFile.patch || ''),
};
}
async function getAgentPyChange(github, owner, repo, prNumber) {
const files = await listPullFiles(github, owner, repo, prNumber);
return getAgentPyChangeFromFiles(files);
}
function touchesSdk(files) {
return files.some((f) => SDK_PATH_PREFIXES.some((p) => f.filename.startsWith(p)));
}
function hasManualOnlyLabel(labels) {
return labels.some((l) => MANUAL_ONLY_LABELS.has(l));
}
function sensitivePathReasons(files, labels = []) {
if (labels.includes(WORKFLOW_ONLY_LABEL) && isCiOnlyChange(files)) {
return [];
}
const reasons = [];
for (const f of files) {
if (SENSITIVE_PATH_PATTERNS.some((p) => p.test(f.filename))) {
reasons.push(`sensitive path: ${f.filename}`);
break;
}
}
return reasons;
}
function prSizeReasons(files) {
const reasons = [];
const totalAdditions = files.reduce((sum, f) => sum + (f.additions || 0), 0);
if (totalAdditions > PR_MAX_AUTO_ADDITIONS) {
reasons.push(`PR +${totalAdditions} lines (>${PR_MAX_AUTO_ADDITIONS}) requires manual review`);
}
if (files.length > PR_MAX_AUTO_FILES) {
reasons.push(`${files.length} files changed (>${PR_MAX_AUTO_FILES}) requires manual review`);
}
return reasons;
}
function missingTestsReason(files) {
const productAdds = files.filter(
(f) =>
SDK_PATH_PREFIXES.some((p) => f.filename.startsWith(p)) &&
f.filename.startsWith('src/praisonaiui/') &&
f.filename.endsWith('.py') &&
!f.filename.endsWith('__init__.py') &&
(f.additions || 0) > 0
);
if (productAdds.length === 0) return null;
const hasTestChange = files.some(
(f) => /\/tests?\//.test(f.filename) || /test_.*\.py$/.test(f.filename) || /_test\.py$/.test(f.filename)
);
if (!hasTestChange) return 'Product code added without test file changes — requires manual review';
return null;
}
function secretScanReasons(files) {
for (const f of files) {
if (/\/tests?\//.test(f.filename) || /test_.*\.py$/.test(f.filename)) continue;
const patch = f.patch || '';
if (!patch) continue;
for (const pattern of SECRET_PATTERNS) {
if (pattern.test(patch)) {
return [`possible secret in diff (${f.filename}) — requires manual review`];
}
}
}
return [];
}
async function sdkTestChecksReason(github, owner, repo, sha, files, core) {
if (!touchesSdk(files)) return null;
const { data } = await github.rest.checks.listForRef({
owner,
repo,
ref: sha,
per_page: 100,
});
const runs = (data.check_runs || []).filter((r) => r.head_sha === sha);
if (runs.length === 0) {
return 'SDK code changed but no CI checks on HEAD';
}
const testRuns = runs.filter((r) => REQUIRED_SDK_CHECK_PATTERNS.some((p) => p.test(r.name || '')));
if (testRuns.length === 0) {
return 'SDK code changed but no test check runs on HEAD';
}
core?.info?.(`SDK test checks on HEAD: ${testRuns.map((r) => r.name).join(', ')}`);
return null;
}
function manualReviewReasonForAgentPy(agentChange) {
if (!agentChange.touched) return null;
if (agentChange.additions > AGENT_PY_MAX_AUTO_LINES) {
return `agent.py +${agentChange.additions} lines (>${AGENT_PY_MAX_AUTO_LINES}) requires manual review`;
}
if (agentChange.newParams > 0) {
return `agent.py adds ${agentChange.newParams} new Agent param(s) — requires manual review`;
}
return null;
}
async function listAllComments(github, owner, repo, issueNumber) {
if (typeof github.paginate === 'function') {
return github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: issueNumber,
per_page: 100,
});
}
const { data } = await github.rest.issues.listComments({
owner,
repo,
issue_number: issueNumber,
per_page: 100,
});
return data;
}
async function getHeadCommitDate(github, owner, repo, prNumber) {
try {
let commits;
if (typeof github.paginate === 'function') {
commits = await github.paginate(github.rest.pulls.listCommits, {
owner,
repo,
pull_number: prNumber,
per_page: 100,
});
} else {
const { data } = await github.rest.pulls.listCommits({
owner,
repo,
pull_number: prNumber,
per_page: 100,
});
commits = data;
}
const last = commits[commits.length - 1];
return last?.commit?.committer?.date || last?.commit?.author?.date || null;
} catch {
return null;
}
}
async function loadPrContext(github, owner, repo, prNumber) {
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
const { data: issue } = await github.rest.issues.get({ owner, repo, issue_number: prNumber });
const comments = await listAllComments(github, owner, repo, prNumber);
const { data: reviews } = await github.rest.pulls.listReviews({
owner,
repo,
pull_number: prNumber,
per_page: 100,
});
const mergeState = await getMergeState(github, owner, repo, prNumber);
const headSha = mergeState.headSha || pr.head.sha;
const headCommitDate = await getHeadCommitDate(github, owner, repo, prNumber);
const headPushedAt = headCommitDate || pr.updated_at;
return {
pr,
issue,
comments,
reviews,
mergeState,
headSha,
headPushedAt,
labels: issue.labels.map((l) => l.name),
baseRepo: `${owner}/${repo}`,
};
}
async function evaluatePipelineQuiescent(github, owner, repo, prNumber, core, options = {}) {
const {
forMergeStep = false,
skipGlobalClaudeRunCheck = false,
skipRecentClaudeCooldown = false,
} = options;
const ctx = await loadPrContext(github, owner, repo, prNumber);
const reasons = [];
if (ctx.pr.draft) reasons.push('draft');
if (ctx.pr.state !== 'open') reasons.push('not open');
if (ctx.labels.includes('auto-merged-by-gate')) reasons.push('already merged by gate');
if (ctx.labels.includes('no-auto-merge')) reasons.push('no-auto-merge label');
if (ctx.labels.includes('claude-conflict-pending')) reasons.push('claude-conflict-pending');
if (!forMergeStep && ctx.labels.includes('claude-merge-gate-active')) {
reasons.push('claude-merge-gate-active');
}
const { status, headRepo, maintainerCanModify } = ctx.mergeState;
if (!ALLOWED_MERGE_STATES.has(status)) reasons.push(`mergeState=${status}`);
if (headRepo && headRepo !== ctx.baseRepo) {
reasons.push('fork PR');
}
if (hasRecentConflictComment(ctx.comments, ctx.headPushedAt)) {
reasons.push('recent merge-conflict @claude');
}
if (!skipRecentClaudeCooldown && hasRecentClaudeTrigger(ctx.comments, 35)) {
const verdictOnHead = findMergeGateVerdict(ctx.comments, null, ctx.headPushedAt) !== null;
if (!verdictOnHead) reasons.push('recent @claude within 35min');
}
if (!skipGlobalClaudeRunCheck && (await hasInProgressClaudeAssistant(github, owner, repo, prNumber))) {
reasons.push('claude.yml in progress');
}
const checksOk = await allChecksGreenOnSha(github, owner, repo, ctx.headSha, core);
if (!checksOk) reasons.push('CI not green on HEAD');
if (!finalClaudeCompletedOnSha(ctx.comments, ctx.headPushedAt)) {
if (!hasFinalClaudeReviewTrigger(ctx.comments)) {
reasons.push('no FINAL Claude review trigger');
} else if (isStaleFinalAfterPush(ctx.comments, ctx.headPushedAt)) {
reasons.push('stale FINAL after new commits (needs @claude re-review)');
} else {
reasons.push('FINAL Claude not complete on HEAD');
}
}
if (hasAnyChangesRequested(ctx.reviews)) reasons.push('CHANGES_REQUESTED review');
if (hasManualOnlyLabel(ctx.labels)) {
const manualLabel = ctx.labels.find((l) => MANUAL_ONLY_LABELS.has(l));
reasons.push(`manual-only label: ${manualLabel}`);
}
const pullFiles = await listPullFiles(github, owner, repo, prNumber);
if (config.agentPyChecks) {
const agentChange = getAgentPyChangeFromFiles(pullFiles);
const agentManual = manualReviewReasonForAgentPy(agentChange);
if (agentManual) reasons.push(agentManual);
}
reasons.push(...sensitivePathReasons(pullFiles, ctx.labels));
reasons.push(...prSizeReasons(pullFiles));
reasons.push(...secretScanReasons(pullFiles));
const testsReason = missingTestsReason(pullFiles);
if (testsReason) reasons.push(testsReason);
const sdkCheckReason = await sdkTestChecksReason(github, owner, repo, ctx.headSha, pullFiles, core);
if (sdkCheckReason) reasons.push(sdkCheckReason);
if (ctx.pr.mergeable === false) reasons.push('not mergeable');
const ready = reasons.length === 0;
return {
ready,
reasons,
headSha: ctx.headSha,
prNumber,
};
}
async function listPrNumbersForMergeGateScan(github, owner, repo, core) {
let mergeReadyIssues;
if (typeof github.paginate === 'function') {
mergeReadyIssues = await github.paginate(github.rest.issues.listForRepo, {
owner,
repo,
state: 'open',
labels: MERGE_READY_LABEL,
per_page: 100,
});
} else {
({ data: mergeReadyIssues } = await github.rest.issues.listForRepo({
owner,
repo,
state: 'open',
labels: MERGE_READY_LABEL,
per_page: 100,
}));
}
const mergeReady = mergeReadyIssues
.filter((issue) => issue.pull_request)
.map((issue) => issue.number)
.sort((a, b) => a - b);
if (mergeReady.length > 0) {
core?.info?.(
`Merge gate scan: ${mergeReady.length} ${MERGE_READY_LABEL} PR(s) (skipping unlabelled open PRs)`
);
return mergeReady;
}
core?.info?.(`No ${MERGE_READY_LABEL} PRs — scanning oldest open PRs`);
const prs =
typeof github.paginate === 'function'
? await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
sort: 'created',
direction: 'asc',
})
: (await github.rest.pulls.list({
owner,
repo,
state: 'open',
per_page: 100,
sort: 'created',
direction: 'asc',
})).data;
return prs.map((pr) => pr.number);
}
async function selectMergeGateCandidates(github, owner, repo, prNumbers, maxCandidates, core) {
const readyList = [];
const skipped = [];
for (const num of prNumbers) {
if (readyList.length >= maxCandidates) {
core?.info?.(`Found ${maxCandidates} candidate(s) — skipping remaining PR scans`);
break;
}
const result = await evaluatePipelineQuiescent(github, owner, repo, num, core);
if (result.ready) {
readyList.push({ pr_number: num, head_sha: result.headSha });
} else {
skipped.push({ pr: num, reasons: result.reasons });
}
}
readyList.sort((a, b) => a.pr_number - b.pr_number);
return {
candidates: readyList.slice(0, maxCandidates),
skipped,
};
}
const AUTOMATED_FALLBACK_MARKER = 'Automated fallback —';
function isAutomatedFallbackVerdict(body) {
return (body || '').includes(AUTOMATED_FALLBACK_MARKER);
}
function findMergeGateVerdict(comments, minCreatedAt = null, headPushedAt = null, options = {}) {
const { excludeAutomatedFallback = false } = options || {};
const minTime = minCreatedAt ? new Date(minCreatedAt).getTime() : 0;
const headTime = headPushedAt ? new Date(headPushedAt).getTime() - 60000 : 0;
const gateComments = comments
.filter((c) => {
if (!(c.body || '').includes('MERGE_GATE_VERDICT:')) return false;
if (excludeAutomatedFallback && isAutomatedFallbackVerdict(c.body)) return false;
const created = new Date(c.created_at).getTime();
if (minTime && created < minTime) return false;
if (headTime && created < headTime) return false;
return true;
})
.sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
if (gateComments.length === 0) return null;
const body = gateComments[0].body || '';
if (body.includes('MERGE_GATE_VERDICT: APPROVE')) return 'APPROVE';
if (body.includes('MERGE_GATE_VERDICT: BLOCK')) return 'BLOCK';
return null;
}
module.exports = {
CLAUDE_TRIGGER_LOGINS,
AUTO_ACTORS,
isFinalClaudeTriggerComment,
isClaudeTriggerNoise,
isClaudeFinalReplyComment,
hasRecentClaudeTrigger,
hasRecentConflictComment,
isConflictRebaseTriggerComment,
isConflictRebaseCompletionComment,
needsFinalReReviewAfterConflictRebase,
conflictRebaseQuiescent,
hasHumanChangesRequested,
hasAnyChangesRequested,
hasFinalClaudeReviewTrigger,
finalClaudeCompletedOnSha,
getMergeState,
OPTIONAL_CANCELLED_CHECKS,
listChecksOnSha,
listFailedChecksOnSha,
allChecksGreenOnSha,
hasInProgressClaudeAssistant,
claudeRunBlocksPr,
hasBlockingClaudeRunForPr,
isCiOnlyChange,
isInternalPullRequestLink,
resolvePrNumberFromLinkedPullRequests,
resolvePrNumberFromHeadBranch,
resolvePrNumberFromWorkflowRun,
WORKFLOW_ONLY_LABEL,
getAgentPyChange,
getAgentPyChangeFromFiles,
manualReviewReasonForAgentPy,
countNewAgentParams,
listPullFiles,
touchesSdk,
hasManualOnlyLabel,
sensitivePathReasons,
prSizeReasons,
missingTestsReason,
secretScanReasons,
sdkTestChecksReason,
listAllComments,
getHeadCommitDate,
isStaleFinalAfterPush,
needsStaleFinalRecovery,
shouldSkipFinalRecovery,
shouldSkipStaleFinalRecovery,
isClaudeAutomationLogin,
isPushSoonAfterLatestFinal,
countFinalTriggersSince,
STALE_FINAL_RECOVERY_WINDOW_MS,
STALE_FINAL_MAX_PER_WINDOW,
FINAL_CLAUDE_REVIEW_BODY,
loadPrContext,
evaluatePipelineQuiescent,
MERGE_READY_LABEL,
listPrNumbersForMergeGateScan,
selectMergeGateCandidates,
isAutomatedFallbackVerdict,
AUTOMATED_FALLBACK_MARKER,
findMergeGateVerdict,
};
@@ -0,0 +1,82 @@
#!/usr/bin/env node
/**
* Run: node .github/scripts/pipeline-status-selftest.js
*/
const ps = require('./pipeline-status.js');
const mg = require('./merge-gate.js');
const config = require('./gate-config.js');
let failed = 0;
function assert(name, cond) {
if (!cond) {
console.error('FAIL:', name);
failed++;
} else {
console.log('ok:', name);
}
}
const kickComments = [
{ user: { login: 'MervinPraison' }, body: '@coderabbitai review' },
{ user: { login: 'MervinPraison' }, body: '/review' },
];
const finalComment = {
user: { login: 'MervinPraison' },
body: '@claude You are the FINAL architecture reviewer.',
created_at: '2026-06-26T10:00:00Z',
};
assert(
'reviews pending when not kicked',
ps.deriveStage([], { ready: false, reasons: ['no FINAL Claude review trigger'] })
=== 'pipeline/reviews-pending'
);
assert(
'final pending after kick',
ps.deriveStage(kickComments, { ready: false, reasons: ['no FINAL Claude review trigger'] })
=== 'pipeline/final-claude-pending'
);
assert(
'awaiting merge gate after bot review comment',
ps.deriveStage(
[
{ user: { login: 'coderabbitai[bot]' }, body: 'review summary' },
finalComment,
],
{ ready: false, reasons: ['recent @claude within 35min'] }
) === 'pipeline/awaiting-merge-gate'
);
assert('review bot logins configured', config.reviewBotLogins.includes('coderabbitai[bot]'));
assert(
'merge ready',
ps.deriveStage([...kickComments, finalComment], { ready: true, reasons: [] })
=== 'pipeline/merge-ready'
);
const blockers = ps.deriveBlockerLabels({
ready: false,
reasons: ['CI not green on HEAD', 'SDK code added without test file changes — requires manual review'],
});
assert('maps ci blocker', blockers.includes('pipeline/blocked:ci'));
assert('maps manual blocker', blockers.includes('pipeline/blocked:manual-review'));
assert(
'internal link matches upstream base',
mg.isInternalPullRequestLink(
{ base: { repo: { full_name: 'MervinPraison/PraisonAI' } } },
'MervinPraison',
'PraisonAI'
)
);
assert(
'fork sync link rejected',
!mg.isInternalPullRequestLink(
{ number: 21, base: { repo: { full_name: 'Milkmange/PraisonAI' } } },
'MervinPraison',
'PraisonAI'
)
);
process.exit(failed ? 1 : 0);
+264
View File
@@ -0,0 +1,264 @@
/**
* Sync pipeline stage/blocker labels on open PRs.
* @see .github/workflows/pipeline-status-sync.yml
*/
const mergeGate = require('./merge-gate.js');
const chain = require('./bot-pr-review-chain.js');
const ciFix = require('./ci-failure-claude.js');
const config = require('./gate-config.js');
const PIPELINE_PREFIX = 'pipeline/';
const STAGE_LABELS = [
'pipeline/reviews-pending',
'pipeline/final-claude-pending',
'pipeline/awaiting-merge-gate',
'pipeline/merge-ready',
'pipeline/merged',
];
const BLOCKER_LABELS = [
'pipeline/blocked:ci',
'pipeline/blocked:conflict',
'pipeline/blocked:manual-review',
'pipeline/blocked:cooldown',
'pipeline/blocked:stale-final',
'pipeline/blocked:no-final',
];
const ALL_PIPELINE_LABELS = [...STAGE_LABELS, ...BLOCKER_LABELS];
const LABEL_SPECS = [
{ name: 'pipeline/reviews-pending', color: 'fbca04', description: 'Waiting for CodeRabbit/Qodo/Copilot reviews' },
{ name: 'pipeline/final-claude-pending', color: 'd4c5f9', description: 'Reviews done; waiting for FINAL @claude' },
{ name: 'pipeline/awaiting-merge-gate', color: 'c5def5', description: 'FINAL done; waiting for merge gate / CI' },
{ name: 'pipeline/merge-ready', color: '0e8a16', description: 'Eligible for merge gate auto-merge' },
{ name: 'pipeline/merged', color: '6f42c1', description: 'Merged via pipeline' },
{ name: 'pipeline/blocked:ci', color: 'd93f0b', description: 'Blocked: CI not green on HEAD' },
{ name: 'pipeline/blocked:conflict', color: 'b60205', description: 'Blocked: merge conflict or rebase pending' },
{ name: 'pipeline/blocked:manual-review', color: 'e99695', description: 'Blocked: requires manual review' },
{ name: 'pipeline/blocked:cooldown', color: 'fef2c0', description: 'Blocked: post-push or @claude cooldown' },
{ name: 'pipeline/blocked:stale-final', color: 'f9d0c4', description: 'Blocked: FINAL stale after new commits' },
{ name: 'pipeline/blocked:no-final', color: 'ededed', description: 'Blocked: no FINAL @claude trigger yet' },
];
function reviewChainStarted(comments) {
if (chain.chainKickPosted(comments)) return true;
return comments.some((c) => config.reviewBotLogins.includes(c.user?.login));
}
function deriveStage(comments, evalResult) {
if (evalResult.ready) return 'pipeline/merge-ready';
if (!reviewChainStarted(comments)) return 'pipeline/reviews-pending';
if (!mergeGate.hasFinalClaudeReviewTrigger(comments)) return 'pipeline/final-claude-pending';
return 'pipeline/awaiting-merge-gate';
}
function reasonToBlockerLabel(reason) {
const r = (reason || '').toLowerCase();
if (r.includes('ci not green') || r.includes('sdk code changed but no ci')) return 'pipeline/blocked:ci';
if (
r.includes('conflict') ||
r.includes('mergestate=dirty') ||
r.includes('not mergeable')
) return 'pipeline/blocked:conflict';
if (
r.includes('manual') ||
r.includes('requires manual') ||
r.includes('sensitive path') ||
r.includes('no-auto-merge') ||
r.includes('manual-only label') ||
r.includes('without test') ||
r.includes('product code') ||
r.includes('files changed') ||
r.includes('possible secret')
) return 'pipeline/blocked:manual-review';
if (r.includes('recent @claude') || r.includes('post-push buffer')) return 'pipeline/blocked:cooldown';
if (r.includes('stale final')) return 'pipeline/blocked:stale-final';
if (r.includes('no final claude')) return 'pipeline/blocked:no-final';
if (r.includes('final claude not complete')) return 'pipeline/blocked:stale-final';
if (r.includes('claude.yml in progress') || r.includes('claude-merge-gate-active')) {
return null;
}
return null;
}
function deriveBlockerLabels(evalResult) {
if (evalResult.ready) return [];
const labels = new Set();
for (const reason of evalResult.reasons || []) {
const mapped = reasonToBlockerLabel(reason);
if (mapped && mapped.startsWith('pipeline/blocked:')) labels.add(mapped);
}
return [...labels];
}
function computePipelineLabels(comments, evalResult) {
const stage = deriveStage(comments, evalResult);
const blockers = stage === 'pipeline/merge-ready' ? [] : deriveBlockerLabels(evalResult);
return { stage, blockers, all: [stage, ...blockers] };
}
async function ensurePipelineLabels(github, owner, repo, core) {
let existing;
if (typeof github.paginate === 'function') {
existing = await github.paginate(github.rest.issues.listLabelsForRepo, {
owner,
repo,
per_page: 100,
});
} else {
({ data: existing } = await github.rest.issues.listLabelsForRepo({
owner,
repo,
per_page: 100,
}));
}
const names = new Set(existing.map((l) => l.name));
for (const spec of LABEL_SPECS) {
if (names.has(spec.name)) continue;
try {
await github.rest.issues.createLabel({
owner,
repo,
name: spec.name,
color: spec.color,
description: spec.description,
});
core?.info?.(`Created label ${spec.name}`);
} catch (err) {
if (err.status !== 422) throw err;
core?.info?.(`Label ${spec.name} already exists`);
}
}
}
async function syncPipelineLabels(github, owner, repo, prNumber, core) {
const ctx = await mergeGate.loadPrContext(github, owner, repo, prNumber);
if (ctx.pr.state !== 'open') return { synced: false, reason: 'not_open' };
const evalResult = await mergeGate.evaluatePipelineQuiescent(
github, owner, repo, prNumber, core
);
const { stage, blockers, all } = computePipelineLabels(ctx.comments, evalResult);
const current = ctx.labels.filter((l) => l.startsWith(PIPELINE_PREFIX));
const desired = new Set(all);
const toRemove = current.filter((l) => !desired.has(l) && l !== 'pipeline/merged');
const toAdd = all.filter((l) => !current.includes(l));
for (const name of toRemove) {
try {
await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name });
} catch (err) {
if (err.status !== 404) throw err;
}
}
if (toAdd.length) {
await github.rest.issues.addLabels({
owner,
repo,
issue_number: prNumber,
labels: toAdd,
});
}
core?.info?.(`PR #${prNumber}: stage=${stage} blockers=[${blockers.join(', ')}]`);
const ciNotGreen = (evalResult.reasons || []).some((r) =>
r.toLowerCase().includes('ci not green')
);
if (ciNotGreen || blockers.includes('pipeline/blocked:ci')) {
await ciFix.maybeTriggerCiFixClaude(github, owner, repo, prNumber, core);
} else {
await ciFix.maybeClearCiFixLabel(
github, owner, repo, prNumber, ctx.labels, ctx.headSha, core
);
}
return {
synced: true,
stage,
blockers,
ready: evalResult.ready,
reasons: evalResult.reasons,
labels: ctx.labels,
createdAt: new Date(ctx.pr.created_at).getTime(),
};
}
async function dispatchMergeGateForOldestReady(github, owner, repo, readyCandidates, core) {
if (!readyCandidates.length) return 0;
readyCandidates.sort((a, b) => a.createdAt - b.createdAt);
for (const cand of readyCandidates) {
if ((cand.labels || []).includes('claude-merge-gate-active')) {
core?.info?.(`Skip dispatch PR #${cand.prNumber}: merge gate already active`);
continue;
}
await github.rest.repos.createDispatchEvent({
owner,
repo,
event_type: 'claude-merge-gate',
client_payload: { pr_number: cand.prNumber },
});
core?.info?.(`Dispatched merge gate for ready PR #${cand.prNumber}`);
return cand.prNumber;
}
return 0;
}
async function syncOpenPullRequests(github, owner, repo, options, core) {
const { maxPrs = 20, dispatchMergeGate = true } = options || {};
await ensurePipelineLabels(github, owner, repo, core);
let prs;
if (maxPrs <= 100) {
({ data: prs } = await github.rest.pulls.list({
owner,
repo,
state: 'open',
per_page: 100,
}));
} else {
prs = await github.paginate(github.rest.pulls.list, {
owner,
repo,
state: 'open',
per_page: 100,
});
}
let synced = 0;
const readyCandidates = [];
for (const pr of prs) {
if (synced >= maxPrs) break;
if (pr.draft) continue;
if (pr.head?.repo?.full_name && pr.head.repo.full_name !== `${owner}/${repo}`) continue;
const result = await syncPipelineLabels(github, owner, repo, pr.number, core);
if (result.ready) {
readyCandidates.push({
prNumber: pr.number,
createdAt: result.createdAt || new Date(pr.created_at).getTime(),
labels: result.labels || [],
});
}
synced += 1;
}
let dispatched = 0;
if (dispatchMergeGate && readyCandidates.length) {
dispatched = await dispatchMergeGateForOldestReady(
github, owner, repo, readyCandidates, core
);
}
core?.info?.(`Pipeline label sync complete (${synced} PR(s), dispatched=${dispatched || 'none'})`);
return synced;
}
module.exports = {
STAGE_LABELS,
BLOCKER_LABELS,
ALL_PIPELINE_LABELS,
deriveStage,
deriveBlockerLabels,
computePipelineLabels,
ensurePipelineLabels,
syncPipelineLabels,
syncOpenPullRequests,
dispatchMergeGateForOldestReady,
};
@@ -0,0 +1,90 @@
#!/usr/bin/env node
const chain = require('./pr-review-chain.js');
let failed = 0;
function assert(name, cond) {
if (!cond) {
console.error('FAIL:', name);
failed++;
} else {
console.log('ok:', name);
}
}
const coderabbit = {
user: { login: 'coderabbitai[bot]' },
body: '<!-- summarize by coderabbit.ai --> summary',
created_at: '2026-07-02T07:16:00Z',
};
const greptile = {
user: { login: 'greptile-apps[bot]' },
body: '<h3>Greptile Summary</h3><p>Looks good</p>',
created_at: '2026-07-02T07:19:00Z',
};
const copilotKick = {
user: { login: 'MervinPraison' },
body: '@copilot Do a thorough review',
created_at: '2026-07-02T07:20:00Z',
};
const copilotReply = {
user: { login: 'copilot-swe-agent' },
body: 'Copilot review here',
created_at: '2026-07-02T07:22:00Z',
};
assert('prior not ready without greptile', !chain.priorReviewersReady([coderabbit]).ready);
assert('prior ready with coderabbit + greptile', chain.priorReviewersReady([coderabbit, greptile]).ready);
assert('copilot not ready before trigger', !chain.copilotReviewReady([coderabbit, greptile]).ready);
assert(
'copilot ready after reply',
chain.copilotReviewReady([coderabbit, greptile, copilotKick, copilotReply]).ready
);
assert(
'claude not ready before copilot',
!chain.claudeFinalReady([coderabbit, greptile]).ready
);
assert(
'claude ready after full chain',
chain.claudeFinalReady([coderabbit, greptile, copilotKick, copilotReply]).ready
);
assert(
'claude timeout fallback when copilot triggered but silent',
chain.claudeFinalReady([coderabbit, greptile, copilotKick], [], { allowCopilotTimeout: true }).ready
);
assert(
'no timeout fallback without copilot trigger',
!chain.claudeFinalReady([coderabbit, greptile], [], { allowCopilotTimeout: true }).ready
);
assert(
'skipCopilot proceeds after prior reviewers',
chain.claudeFinalReady([coderabbit, greptile], [], { skipCopilot: true }).ready
);
const oldPr = new Date(Date.now() - 31 * 60 * 1000).toISOString();
assert(
'prior not ready without coderabbit before timeout',
!chain.priorReviewersReady([greptile], [], { prCreatedAt: new Date().toISOString(), requiredWaitMs: 30 * 60 * 1000 }).ready
);
assert(
'prior timeout when coderabbit silent after 30m',
chain.priorReviewersReady([greptile], [], { prCreatedAt: oldPr, requiredWaitMs: 30 * 60 * 1000 }).ready
);
assert(
'claude FINAL timeout when required reviewer silent and no prior FINAL',
chain.claudeFinalReady([greptile], [], { prCreatedAt: oldPr, requiredWaitMs: 30 * 60 * 1000 }).ready
);
assert(
'claude FINAL timeout auto-skips copilot without explicit skipCopilot',
chain.claudeFinalReady([greptile], [], { prCreatedAt: oldPr, requiredWaitMs: 30 * 60 * 1000 }).copilotSkipped
);
const finalClaude = {
user: { login: 'github-actions[bot]' },
body: '@claude You are the FINAL architecture reviewer for this PR.',
created_at: '2026-07-02T07:25:00Z',
};
assert(
'claude FINAL not re-posted when already triggered',
!chain.claudeFinalReady([greptile, finalClaude], [], { prCreatedAt: oldPr, requiredWaitMs: 0 }).ready
);
process.exit(failed ? 1 : 0);
+319
View File
@@ -0,0 +1,319 @@
/**
* PR review pipeline: CodeRabbit / Greptile (+ optional Qodo/Gemini) → Claude (FINAL).
* Copilot step optional — set REVIEW_CHAIN_SKIP_COPILOT=1 or skipCopilot: true to bypass.
* @see .github/workflows/auto-pr-comment.yml
*/
function isSkipCopilot(options = {}) {
if (options.skipCopilot === true) return true;
if (options.skipCopilot === false) return false;
return process.env.REVIEW_CHAIN_SKIP_COPILOT === '1';
}
const COPILOT_TRIGGER_LOGINS = new Set(['MervinPraison', 'github-actions[bot]']);
const CLAUDE_TRIGGER_LOGINS = new Set(['MervinPraison', 'github-actions[bot]']);
const REQUIRED_PRIOR = ['coderabbit', 'greptile'];
const OPTIONAL_PRIOR = ['qodo', 'gemini'];
const OPTIONAL_PRIOR_WAIT_MS = 20 * 60 * 1000;
const REQUIRED_PRIOR_WAIT_MS = 30 * 60 * 1000;
function loginOf(item) {
return (item?.user?.login || '').toLowerCase();
}
function bodyOf(item) {
return item?.body || '';
}
function hasCoderabbitSummary(comments) {
return comments.some(
(c) =>
loginOf(c).includes('coderabbit') &&
bodyOf(c).toLowerCase().includes('summarize by coderabbit')
);
}
function hasGreptileReview(comments) {
return comments.some((c) => {
if (!loginOf(c).includes('greptile')) return false;
const body = bodyOf(c);
return body.includes('Greptile Summary') || body.includes('<h3>Greptile Summary</h3>') || body.length > 150;
});
}
function hasQodoReview(comments, reviews = []) {
if (comments.some((c) => loginOf(c).includes('qodo'))) return true;
return reviews.some((r) => loginOf(r).includes('qodo'));
}
function hasGeminiReview(comments, reviews = []) {
if (reviews.some((r) => loginOf(r).includes('gemini'))) return true;
return comments.some((c) => {
if (loginOf(c).includes('gemini')) return true;
const body = bodyOf(c);
return (
body.includes('Review completed by Gemini CLI') ||
body.includes('The fix is ready for review. Please test')
);
});
}
const PRIOR_CHECKS = {
coderabbit: (comments) => hasCoderabbitSummary(comments),
greptile: (comments) => hasGreptileReview(comments),
qodo: (comments, reviews) => hasQodoReview(comments, reviews),
gemini: (comments, reviews) => hasGeminiReview(comments, reviews),
};
function priorReviewerStatus(comments, reviews = []) {
const status = {};
for (const [id, check] of Object.entries(PRIOR_CHECKS)) {
status[id] = check(comments, reviews);
}
return status;
}
function priorReviewersReady(comments, reviews = [], options = {}) {
const waitMs = options.optionalWaitMs ?? OPTIONAL_PRIOR_WAIT_MS;
const requiredWaitMs = options.requiredWaitMs ?? REQUIRED_PRIOR_WAIT_MS;
const prCreatedAt = options.prCreatedAt || null;
const status = priorReviewerStatus(comments, reviews);
const missingRequired = REQUIRED_PRIOR.filter((id) => !status[id]);
if (missingRequired.length) {
if (prCreatedAt) {
const age = Date.now() - new Date(prCreatedAt).getTime();
if (age >= requiredWaitMs) {
return {
ready: true,
reason: `required reviewer timeout (${missingRequired.join(', ')} silent after ${Math.round(requiredWaitMs / 60000)}m)`,
status,
requiredTimeout: true,
};
}
}
return { ready: false, reason: `waiting for ${missingRequired.join(', ')}`, status };
}
const missingOptional = OPTIONAL_PRIOR.filter((id) => !status[id]);
if (missingOptional.length && prCreatedAt) {
const age = Date.now() - new Date(prCreatedAt).getTime();
if (age < waitMs) {
return {
ready: false,
reason: `waiting for optional ${missingOptional.join(', ')} (${Math.round((waitMs - age) / 60000)}m left)`,
status,
};
}
}
return { ready: true, reason: '', status };
}
function copilotTriggerComment(comments) {
return comments.find(
(c) =>
bodyOf(c).includes('@copilot') &&
COPILOT_TRIGGER_LOGINS.has(c.user?.login) &&
!bodyOf(c).toLowerCase().includes('@claude')
);
}
function copilotTriggered(comments) {
return Boolean(copilotTriggerComment(comments));
}
function copilotReviewReady(comments, reviews = []) {
const trigger = copilotTriggerComment(comments);
if (!trigger) {
return { ready: false, reason: 'copilot not triggered yet' };
}
const triggerTime = new Date(trigger.created_at).getTime();
const copilotComment = comments.some((c) => {
if (c === trigger) return false;
if (new Date(c.created_at).getTime() < triggerTime) return false;
const login = loginOf(c);
return (
login.includes('copilot') ||
c.user?.login === 'Copilot' ||
c.user?.login === 'copilot-swe-agent'
);
});
const copilotReview = reviews.some((r) => {
if (new Date(r.submitted_at).getTime() < triggerTime) return false;
return loginOf(r).includes('copilot');
});
if (copilotComment || copilotReview) {
return { ready: true, reason: '' };
}
return { ready: false, reason: 'awaiting copilot review' };
}
function isFinalClaudeTriggerComment(c) {
const body = bodyOf(c).toLowerCase();
if (!CLAUDE_TRIGGER_LOGINS.has(c.user?.login)) return false;
if (!body.includes('@claude')) return false;
if (body.includes('merge conflict')) return false;
return body.includes('final architecture reviewer') || body.includes('lead engineer');
}
function claudeFinalAlreadyTriggered(comments) {
return comments.some(isFinalClaudeTriggerComment);
}
function claudeFinalReady(comments, reviews = [], options = {}) {
if (!options.allowStaleRepost && claudeFinalAlreadyTriggered(comments)) {
return { ready: false, reason: 'claude FINAL already triggered', already: true };
}
const prior = priorReviewersReady(comments, reviews, options);
if (!prior.ready) {
return { ready: false, reason: prior.reason };
}
if (isSkipCopilot(options) || prior.requiredTimeout) {
return {
ready: true,
reason: prior.requiredTimeout ? prior.reason : 'copilot skipped',
copilotSkipped: true,
requiredTimeout: prior.requiredTimeout,
};
}
const copilot = copilotReviewReady(comments, reviews);
if (copilot.ready) {
return { ready: true, reason: '' };
}
if (options.allowCopilotTimeout && copilotTriggered(comments)) {
return { ready: true, reason: 'copilot timeout fallback', copilotSkipped: true };
}
return { ready: false, reason: copilot.reason };
}
/** Post @copilot when prior reviewers are ready, then @claude FINAL when Copilot done (or timeout). */
async function advanceReviewChain(github, owner, repo, prNumber, finalBody, core, options = {}) {
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
const chainOpts = {
prCreatedAt: pr.created_at,
optionalWaitMs: options.optionalWaitMs ?? 0,
};
const copilot = options.skipCopilot
? { triggered: false, reason: 'skipped' }
: await maybeTriggerCopilot(github, owner, repo, prNumber, core, chainOpts);
const claude = await maybeTriggerClaudeFinal(
github, owner, repo, prNumber, finalBody, core,
{ ...options, ...chainOpts }
);
return { copilot, claude };
}
async function maybeTriggerClaudeFinal(github, owner, repo, prNumber, finalBody, core, options = {}) {
const { data: pr } = await github.rest.pulls.get({ owner, repo, pull_number: prNumber });
const { comments, reviews } = await listCommentsAndReviews(github, owner, repo, prNumber);
const gate = claudeFinalReady(comments, reviews, {
prCreatedAt: pr.created_at,
optionalWaitMs: options.optionalWaitMs,
allowCopilotTimeout: options.allowCopilotTimeout !== false,
allowStaleRepost: options.allowStaleRepost === true,
skipCopilot: options.skipCopilot,
});
if (!gate.ready) {
core?.info?.(`PR #${prNumber}: skip Claude FINAL — ${gate.reason}`);
return { posted: false, reason: gate.reason };
}
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: finalBody,
});
const note = gate.copilotSkipped ? ' (Copilot timeout fallback)' : '';
core?.info?.(`Posted Claude FINAL on PR #${prNumber}${note}`);
return { posted: true, reason: '' };
}
const COPILOT_REVIEW_BODY =
'@copilot Do a thorough review of this PR. Read ALL existing reviewer comments above from Qodo, CodeRabbit, Gemini, and Greptile first — incorporate their findings.\n\nReview areas:\n1. **Bloat check**: Are changes minimal and focused? Any unnecessary code or scope creep?\n2. **Security**: Any hardcoded secrets, unsafe eval/exec, missing input validation?\n3. **Performance**: Any module-level heavy imports? Hot-path regressions?\n4. **Tests**: Are tests included? Do they cover the changes adequately?\n5. **Backward compat**: Any public API changes without deprecation?\n6. **Code quality**: DRY violations, naming conventions, error handling?\n7. **Address reviewer feedback**: If Qodo, CodeRabbit, Gemini, or Greptile flagged valid issues, include them in your review\n8. Suggest specific improvements with code examples where possible';
async function listCommentsAndReviews(github, owner, repo, prNumber) {
let comments;
if (typeof github.paginate === 'function') {
comments = await github.paginate(github.rest.issues.listComments, {
owner,
repo,
issue_number: prNumber,
per_page: 100,
});
} else {
const { data } = await github.rest.issues.listComments({
owner,
repo,
issue_number: prNumber,
per_page: 100,
});
comments = data;
}
const { data: reviews } = await github.rest.pulls.listReviews({
owner,
repo,
pull_number: prNumber,
per_page: 100,
});
return { comments, reviews };
}
async function maybeTriggerCopilot(github, owner, repo, prNumber, core, options = {}) {
const { comments, reviews } = await listCommentsAndReviews(github, owner, repo, prNumber);
if (copilotTriggered(comments)) {
core?.info?.(`Copilot already triggered on PR #${prNumber}`);
return { triggered: false, reason: 'already_triggered' };
}
const prior = priorReviewersReady(comments, reviews, options);
if (!prior.ready) {
core?.info?.(`PR #${prNumber}: not ready for Copilot — ${prior.reason}`);
return { triggered: false, reason: prior.reason };
}
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: COPILOT_REVIEW_BODY,
});
core?.info?.(`Posted @copilot on PR #${prNumber} after prior reviewers`);
return { triggered: true };
}
async function pollCopilotResponse(github, owner, repo, prNumber, options = {}) {
const maxAttempts = options.maxAttempts ?? 20;
const delayMs = options.delayMs ?? 30000;
for (let i = 0; i < maxAttempts; i += 1) {
const { comments, reviews } = await listCommentsAndReviews(github, owner, repo, prNumber);
const copilot = copilotReviewReady(comments, reviews);
if (copilot.ready) {
return { ready: true, reason: '' };
}
if (i < maxAttempts - 1) {
await new Promise((resolve) => setTimeout(resolve, delayMs));
}
}
return { ready: false, reason: 'copilot timeout' };
}
module.exports = {
isSkipCopilot,
REQUIRED_PRIOR,
OPTIONAL_PRIOR,
REQUIRED_PRIOR_WAIT_MS,
COPILOT_REVIEW_BODY,
priorReviewerStatus,
priorReviewersReady,
copilotTriggered,
copilotReviewReady,
claudeFinalReady,
claudeFinalAlreadyTriggered,
isFinalClaudeTriggerComment,
maybeTriggerCopilot,
maybeTriggerClaudeFinal,
advanceReviewChain,
pollCopilotResponse,
hasGeminiReview,
listCommentsAndReviews,
};
+32
View File
@@ -0,0 +1,32 @@
#!/usr/bin/env node
/**
* Run: node .github/scripts/release-gate-selftest.js
*/
const rg = require('./release-gate.js');
const config = require('./gate-config.js');
let failed = 0;
function assert(name, cond) {
if (!cond) {
console.error('FAIL:', name);
failed += 1;
} else {
console.log('ok:', name);
}
}
assert('package name is aiui', config.pypiPackageName === 'aiui');
assert('bumpPatch works', rg.bumpPatch('0.3.127') === '0.3.128');
try {
const versions = rg.readVersionsFromTree(process.cwd());
assert('reads current version', /^\d+\.\d+\.\d+$/.test(versions.current));
assert('computes target patch', versions.target === rg.bumpPatch(versions.current));
} catch (err) {
console.error('FAIL: readVersionsFromTree', err.message);
failed += 1;
}
assert('PACKAGE_PATHS includes pyproject', rg.PACKAGE_PATHS.includes('pyproject.toml'));
process.exit(failed ? 1 : 0);
+205
View File
@@ -0,0 +1,205 @@
/**
* Release gate preflight — path changes, CI SHA, dedupe, PyPI version checks (PraisonAIUI).
*/
const https = require('https');
const config = require('./gate-config.js');
const PACKAGE_PATHS = config.packagePaths;
const ACTIVE_RELEASE_STATUSES = new Set([
'queued', 'in_progress', 'waiting', 'pending', 'requested',
]);
function bumpPatch(version) {
const parts = version.split('.');
if (parts.length !== 3) throw new Error(`Invalid version: ${version}`);
return `${parts[0]}.${parts[1]}.${Number(parts[2]) + 1}`;
}
function readVersionsFromTree(root = '.') {
const fs = require('fs');
const path = require('path');
const toml = fs.readFileSync(path.join(root, 'pyproject.toml'), 'utf8');
const match = toml.match(/^version\s*=\s*"([^"]+)"/m);
if (!match) throw new Error('Could not read aiui version from pyproject.toml');
const current = match[1];
const target = bumpPatch(current);
return { current, target, packageName: config.pypiPackageName };
}
function pypiVersionExists(packageName, version) {
return new Promise((resolve) => {
const req = https.get(
`https://pypi.org/pypi/${packageName}/${version}/json`,
{ timeout: 15000 },
(res) => {
res.resume();
resolve(res.statusCode === 200);
}
);
req.on('error', () => resolve(false));
req.on('timeout', () => {
req.destroy();
resolve(false);
});
});
}
async function hasActiveReleaseRun(github, owner, repo) {
const runs = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: 'pypi-release.yml',
per_page: 20,
});
return runs.data.workflow_runs.some(
(r) => ACTIVE_RELEASE_STATUSES.has(r.status) && !r.conclusion
);
}
function utcDayStart(now = new Date()) {
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
}
async function hasSuccessfulReleaseToday(github, owner, repo, now = new Date()) {
const dayStart = utcDayStart(now);
const runs = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: 'pypi-release.yml',
status: 'completed',
per_page: 30,
});
return runs.data.workflow_runs.some(
(r) => r.conclusion === 'success' && new Date(r.created_at) >= dayStart
);
}
async function lastGreenCiSha(github, owner, repo) {
const runs = await github.rest.actions.listWorkflowRuns({
owner,
repo,
workflow_id: config.ciWorkflowFile,
branch: 'main',
status: 'completed',
per_page: 30,
});
const hit = runs.data.workflow_runs.find((r) => r.conclusion === 'success');
return hit ? hit.head_sha : '';
}
async function evaluateReleasePreflight(github, owner, repo, options, core) {
const {
headSha,
isCiTrigger = false,
bump = 'patch',
} = options;
const reasons = [];
const out = {
ready: false,
reasons,
headSha: headSha || '',
lastTag: '',
targetVersion: '',
packageName: config.pypiPackageName,
};
if (bump !== 'patch') {
reasons.push('only patch auto-release supported');
return out;
}
if (await hasActiveReleaseRun(github, owner, repo)) {
reasons.push('PyPI Release already in progress or awaiting approval');
return out;
}
const referenceTime = options.now instanceof Date ? options.now : new Date();
if (await hasSuccessfulReleaseToday(github, owner, repo, referenceTime)) {
const day = referenceTime.toISOString().slice(0, 10);
reasons.push(`already released today (UTC ${day}); max one patch release per day`);
return out;
}
let versions;
try {
versions = readVersionsFromTree();
} catch (err) {
reasons.push(err.message);
return out;
}
out.targetVersion = versions.target;
const onPypi = await pypiVersionExists(config.pypiPackageName, versions.target);
if (onPypi) {
reasons.push(`already published: ${config.pypiPackageName}==${versions.target}`);
return out;
}
const { execSync } = require('child_process');
let lastTag = '';
try {
lastTag = execSync('git describe --tags --match "v*" --abbrev=0', { encoding: 'utf8' }).trim();
} catch {
reasons.push('no v* tag found');
return out;
}
out.lastTag = lastTag;
let changed = '';
try {
changed = execSync(
`git diff --name-only ${lastTag} HEAD -- ${PACKAGE_PATHS.join(' ')}`,
{ encoding: 'utf8' }
).trim();
} catch {
reasons.push('git diff failed');
return out;
}
if (!changed) {
reasons.push(`no changes in ${PACKAGE_PATHS.join(' or ')} since ${lastTag}`);
return out;
}
if (isCiTrigger) {
let mainSha = '';
try {
mainSha = execSync('git rev-parse origin/main', { encoding: 'utf8' }).trim();
} catch {
reasons.push('could not resolve origin/main');
return out;
}
if (headSha !== mainSha) {
reasons.push(`superseded: green SHA ${headSha.slice(0, 7)} != main ${mainSha.slice(0, 7)}`);
return out;
}
out.headSha = headSha;
} else {
const evalSha = execSync('git rev-parse HEAD', { encoding: 'utf8' }).trim();
out.headSha = evalSha;
const greenSha = await lastGreenCiSha(github, owner, repo);
if (greenSha !== evalSha) {
reasons.push(`CI not green on HEAD (last green: ${greenSha ? greenSha.slice(0, 7) : 'none'})`);
return out;
}
}
out.ready = true;
out.reasons = ['ready'];
if (core) core.info(`Release preflight passed for ${out.headSha || headSha}`);
return out;
}
module.exports = {
bumpPatch,
readVersionsFromTree,
pypiVersionExists,
hasSuccessfulReleaseToday,
utcDayStart,
evaluateReleasePreflight,
lastGreenCiSha,
ACTIVE_RELEASE_STATUSES,
PACKAGE_PATHS,
};
+95
View File
@@ -0,0 +1,95 @@
name: Auto Issue Comment
# Automatically escalate every new issue to Claude for a full investigation
# + draft fix. Manual re-trigger: workflow_dispatch with issue_number.
#
# Note: `@claude` mentions only trigger claude.yml when the commenter is a
# HUMAN user (or github-actions[bot] via PAT). This workflow posts the
# comment as github-actions[bot], so claude.yml must allow that bot.
on:
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to triage with Claude"
required: true
type: string
issues:
types: [opened]
jobs:
# Escalate an issue to full Claude implementation by adding the `claude`
# label. claude.yml listens on `issues:labeled` + label=='claude' and
# triggers Job 2 (claude-response) which does the actual work.
trigger-claude:
if: |
github.event_name == 'workflow_dispatch' ||
github.event_name == 'issues'
runs-on: ubuntu-latest
permissions:
issues: write
actions: write
steps:
- name: Resolve issue number
id: resolve
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "number=${{ inputs.issue_number }}" >> "$GITHUB_OUTPUT"
else
echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT"
fi
- name: Add claude label + post instructions
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GH_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const issueNumber = Number('${{ steps.resolve.outputs.number }}');
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
});
const labels = (issue.labels || []).map(l => typeof l === 'string' ? l : l.name);
const hadClaude = labels.includes('claude');
if (!hadClaude) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
labels: ['claude'],
});
} else {
console.log(`Issue #${issueNumber} already has 'claude' label — dispatching Claude only.`);
}
const body = [
'🤖 Auto-triaging with Claude.',
'',
'Claude will:',
'',
'1. Read this issue and all comments.',
'2. Classify and route to the right area (`src/praisonaiui/`, `src/frontend/`, `docs/`, or external repo).',
'3. Implement a minimal fix per `AGENTS.md`.',
'4. Run `pytest` + the import-time invariant locally.',
'5. Open a draft PR linked to this issue.',
'',
'Follow-ups in this thread with `@claude` will re-trigger the loop.'
].join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issueNumber,
body,
});
await github.rest.actions.createWorkflowDispatch({
owner: context.repo.owner,
repo: context.repo.repo,
workflow_id: 'claude.yml',
ref: 'main',
inputs: { issue_number: String(issueNumber) },
});
console.log(`Dispatched Claude Assistant for issue #${issueNumber}`);
+33
View File
@@ -0,0 +1,33 @@
name: Auto PR Comment
on:
issue_comment:
types: [created]
pull_request_review:
types: [submitted]
pull_request:
types: [opened, synchronize]
pull_request_target:
types: [opened, synchronize]
schedule:
- cron: '30 * * * *'
workflow_dispatch:
env:
REVIEW_CHAIN_SKIP_COPILOT: '1'
permissions:
issues: write
pull-requests: write
jobs:
review-chain:
# Grant union of callee job permissions (repos with default_workflow_permissions: read
# reject reusable calls when the caller ceiling is lower than any callee job).
permissions:
issues: write
pull-requests: write
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.19
+23
View File
@@ -0,0 +1,23 @@
name: Bot PR Recovery
on:
schedule:
- cron: '*/15 * * * *'
workflow_dispatch:
inputs:
pr_number:
description: 'Specific PR number to kick (optional)'
required: false
type: string
permissions:
pull-requests: write
issues: write
jobs:
recover:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.19
pr_number: ${{ github.event.inputs.pr_number || '' }}
+32
View File
@@ -0,0 +1,32 @@
name: Auto CI Failure → Claude
on:
workflow_run:
workflows: [Core Tests, Optimized Test Suite]
types: [completed]
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
inputs:
pr_number:
required: false
type: string
schedule:
- cron: '15 */6 * * *'
concurrency:
group: ci-failure-scan-${{ github.repository }}-${{ github.event.pull_request.number || github.event.workflow_run.id || github.run_id }}
cancel-in-progress: true
permissions:
pull-requests: read
issues: write
actions: read
jobs:
detect-and-trigger:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.19
pr_number: ${{ github.event.inputs.pr_number || '' }}
+93
View File
@@ -0,0 +1,93 @@
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
python:
name: python
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: pip install -e .[dev]
- name: Lint with ruff
run: ruff check src/praisonaiui
- name: Test with pytest
# Unit tests are the primary CI contract; integration smoke validates backends.
run: pytest tests/unit -v --no-cov --timeout=60
- name: Integration smoke tests
run: pytest tests/integration/test_agentic_roundtrip.py tests/test_feature_sdk_backends.py -q --no-cov --timeout=120
frontend:
name: frontend
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
cache: npm
cache-dependency-path: src/frontend/package-lock.json
- name: Install dependencies
run: npm ci
working-directory: src/frontend
# `npm run build` is the dashboard ship path: dist/ is synced to
# src/praisonaiui/templates/frontend/ (see src/frontend/README.md).
- name: Build frontend
run: npm run build
working-directory: src/frontend
docs:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
permissions:
contents: write
pages: write
id-token: write
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install AIUI
run: pip install -e .
- name: Build docs with AIUI
run: |
aiui build --output site --minify
cp CNAME site/CNAME
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
force_orphan: true
+96
View File
@@ -0,0 +1,96 @@
name: Claude PR Merge Gate
on:
schedule:
- cron: '*/10 * * * *'
workflow_dispatch:
inputs:
pr_number:
required: false
type: string
merge_method:
required: false
type: choice
default: merge
options: [merge, squash, rebase]
workflow_run:
workflows:
- Claude Assistant
- Core Tests
types: [completed]
repository_dispatch:
types: [claude-merge-gate]
concurrency:
group: claude-merge-gate-${{ github.repository }}-${{ github.event.inputs.pr_number || github.event.client_payload.pr_number || github.event.workflow_run.id || 'scan' }}
cancel-in-progress: false
permissions:
contents: read
pull-requests: read
issues: read
actions: read
jobs:
auto-dispatch:
if: github.event_name == 'workflow_run'
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
actions: write
id-token: write
steps:
- uses: actions/checkout@v4
- uses: MervinPraison/github-automation-template/.github/actions/[email protected]
with:
hub_ref: v1.1.19
- name: Generate GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ secrets.CLAUDE_APP_ID }}
private-key: ${{ secrets.CLAUDE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Dispatch merge gate when PR pipeline is ready
uses: actions/github-script@v7
with:
github-token: ${{ steps.app-token.outputs.token }}
script: |
const path = require('path');
const mergeGate = require(path.join(process.env.HUB_SCRIPTS, 'merge-gate.js'));
const wr = context.payload.workflow_run;
const owner = context.repo.owner;
const repo = context.repo.repo;
if (wr.conclusion !== 'success') return;
const allowed = ['Claude Assistant', 'Core Tests'];
if (!allowed.includes(wr.name)) return;
const prNumber = await mergeGate.resolvePrNumberFromWorkflowRun(github, owner, repo, wr);
if (!prNumber) return;
const fromClaude = wr.name === 'Claude Assistant';
const check = await mergeGate.evaluatePipelineQuiescent(github, owner, repo, prNumber, core, {
skipGlobalClaudeRunCheck: fromClaude,
skipRecentClaudeCooldown: fromClaude,
});
if (!check.ready) return;
await github.rest.repos.createDispatchEvent({
owner, repo, event_type: 'claude-merge-gate',
client_payload: { pr_number: prNumber },
});
merge-gate:
if: github.event_name != 'workflow_run'
permissions:
contents: write
pull-requests: write
issues: write
actions: read
id-token: write
statuses: write # the assess job records security/outsider-review
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.19
pr_number: ${{ github.event.inputs.pr_number || github.event.client_payload.pr_number || '' }}
merge_method: ${{ github.event.inputs.merge_method || 'merge' }}
+24
View File
@@ -0,0 +1,24 @@
name: Claude Assistant
on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [assigned, labeled, opened]
pull_request_review:
types: [submitted]
jobs:
claude:
permissions:
contents: write
pull-requests: write
issues: write
actions: read
id-token: write
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.19
+41
View File
@@ -0,0 +1,41 @@
name: Deploy Docs
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: write
pages: write
id-token: write
concurrency:
group: deploy-docs
cancel-in-progress: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install AIUI
run: pip install -e .
- name: Build docs with AIUI
run: |
aiui build --output site --minify
cp CNAME site/CNAME
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
force_orphan: true
@@ -0,0 +1,52 @@
name: Auto Merge Conflict → Claude
on:
push:
branches: [main]
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
schedule:
- cron: '0 */6 * * *'
concurrency:
group: merge-conflict-scan-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
permissions:
pull-requests: write
issues: write
jobs:
detect-and-trigger:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: MervinPraison/github-automation-template/.github/actions/[email protected]
with:
hub_ref: v1.1.19
- name: Detect conflicting PRs and trigger Claude
uses: actions/github-script@v7
with:
github-token: ${{ env.GH_TOKEN }}
script: |
const path = require('path');
const mg = require(path.join(process.env.HUB_SCRIPTS, 'merge-gate.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const baseRepo = `${owner}/${repo}`;
const prs = await github.paginate(github.rest.pulls.list, { owner, repo, state: 'open', per_page: 50 });
for (const pr of prs) {
if (pr.draft) continue;
if (pr.head?.repo?.full_name !== baseRepo) continue;
const state = await mg.getMergeState(github, owner, repo, pr.number);
if (state.status !== 'DIRTY') continue;
const { data: comments } = await github.rest.issues.listComments({ owner, repo, issue_number: pr.number, per_page: 100 });
if (mg.hasRecentConflictComment(comments)) continue;
const body = '@claude this PR has merge conflicts with `main`. Rebase onto latest main, resolve conflicts, run tests, force-push with --force-with-lease.';
await github.rest.issues.createComment({ owner, repo, issue_number: pr.number, body });
await github.rest.issues.addLabels({ owner, repo, issue_number: pr.number, labels: ['claude-conflict-pending'] });
}
+129
View File
@@ -0,0 +1,129 @@
name: Nightly Release Gate
# Preflight before PyPI Release (patch bump).
# Primary: CI success on main (workflow_run).
# Backstop: nightly cron at 00:00 UTC.
on:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
inputs:
dry_run:
description: 'Run preflight only; do not dispatch pypi-release.yml'
required: false
default: false
type: boolean
workflow_run:
workflows:
- CI
types:
- completed
branches:
- main
permissions:
contents: read
actions: write
concurrency:
group: nightly-release-gate
cancel-in-progress: false
jobs:
preflight:
if: |
github.event_name == 'workflow_dispatch' ||
github.event_name == 'schedule' ||
(
github.event_name == 'workflow_run' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.head_branch == 'main' &&
github.event.workflow_run.event == 'push'
)
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
steps:
- name: Resolve trigger context
id: ctx
run: |
if [ "${{ github.event_name }}" = "workflow_run" ]; then
echo "checkout_sha=${{ github.event.workflow_run.head_sha }}" >> "$GITHUB_OUTPUT"
echo "source=ci" >> "$GITHUB_OUTPUT"
echo "is_ci=true" >> "$GITHUB_OUTPUT"
else
echo "checkout_sha=main" >> "$GITHUB_OUTPUT"
echo "source=nightly" >> "$GITHUB_OUTPUT"
echo "is_ci=false" >> "$GITHUB_OUTPUT"
fi
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: ${{ steps.ctx.outputs.checkout_sha }}
fetch-depth: 0
- name: Fetch main and tags
run: git fetch --tags origin main
- name: Preflight — path changes, CI SHA, dedupe
id: preflight
uses: actions/github-script@v7
env:
HEAD_SHA: ${{ steps.ctx.outputs.checkout_sha }}
IS_CI: ${{ steps.ctx.outputs.is_ci }}
with:
github-token: ${{ secrets.GH_TOKEN }}
script: |
const path = require('path');
const rg = require(path.join(process.env.GITHUB_WORKSPACE, '.github/scripts/release-gate.js'));
const owner = context.repo.owner;
const repo = context.repo.repo;
const headSha = process.env.HEAD_SHA;
const isCi = process.env.IS_CI === 'true';
const result = await rg.evaluateReleasePreflight(
github, owner, repo,
{ headSha, isCiTrigger: isCi, bump: 'patch' },
core
);
core.setOutput('should_release', result.ready ? 'true' : 'false');
core.setOutput('reason', result.reasons.join('; '));
core.setOutput('head_sha', result.headSha || headSha);
core.setOutput('last_tag', result.lastTag || '');
core.setOutput('target_version', result.targetVersion || '');
core.summary.addRaw('## Release gate preflight\n');
core.summary.addRaw(`Ready: ${result.ready}\n`);
core.summary.addRaw(`Reason: ${result.reasons.join('; ')}\n`);
if (result.targetVersion) {
core.summary.addRaw(`Target: aiui==${result.targetVersion}\n`);
}
await core.summary.write();
if (!result.ready) {
core.info(`Skip release: ${result.reasons.join('; ')}`);
}
- name: Dry run summary
if: inputs.dry_run == true
run: |
echo "Dry run — preflight only, no pypi-release dispatch."
echo "should_release=${{ steps.preflight.outputs.should_release }}"
echo "reason=${{ steps.preflight.outputs.reason }}"
- name: Dispatch PyPI Release (patch)
if: steps.preflight.outputs.should_release == 'true' && inputs.dry_run != true
run: |
set -euo pipefail
gh workflow run pypi-release.yml \
--repo "${GITHUB_REPOSITORY}" \
--ref main \
-f bump=patch \
-f source=${{ steps.ctx.outputs.source }} \
-f trigger_sha=${{ steps.preflight.outputs.head_sha }} \
-f dry_run=false
echo "Dispatched pypi-release.yml (patch, source=${{ steps.ctx.outputs.source }})"
echo "Uses pypi-auto environment for ci/nightly patch releases."
@@ -0,0 +1,19 @@
name: Pipeline Status Sync
on:
schedule:
- cron: '*/10 * * * *'
workflow_dispatch:
permissions:
pull-requests: read
issues: write
actions: write
id-token: write
jobs:
sync:
uses: MervinPraison/github-automation-template/.github/workflows/[email protected]
secrets: inherit
with:
hub_ref: v1.1.19
+232
View File
@@ -0,0 +1,232 @@
name: PyPI Release
# Requires GitHub Environment "pypi" (manual) or "pypi-auto" (ci/nightly patch).
# Secrets: PYPI_TOKEN (or PYPI_API_TOKEN), GH_TOKEN
on:
workflow_dispatch:
inputs:
bump:
description: 'Version bump type for aiui'
required: true
default: patch
type: choice
options:
- patch
- minor
- major
dry_run:
description: 'Preview versions and steps without publishing or pushing'
required: false
default: false
type: boolean
version:
description: 'Override version (empty = auto bump from pyproject.toml)'
required: false
default: ''
type: string
source:
description: 'Trigger source (audit trail)'
required: false
default: manual
type: string
trigger_sha:
description: 'SHA that triggered this release'
required: false
default: ''
type: string
permissions:
contents: write
concurrency:
group: pypi-release
cancel-in-progress: false
jobs:
release:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: >-
${{
(inputs.source == 'ci' || inputs.source == 'nightly') &&
inputs.bump == 'patch' &&
'pypi-auto' || 'pypi'
}}
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN || secrets.PYPI_API_TOKEN }}
GH_TOKEN: ${{ secrets.GH_TOKEN }}
PACKAGE: aiui
steps:
- name: Release audit
run: |
echo "Source: ${{ inputs.source }}"
echo "Trigger SHA: ${{ inputs.trigger_sha }}"
echo "Bump: ${{ inputs.bump }}"
echo "Environment: ${{ (inputs.source == 'ci' || inputs.source == 'nightly') && inputs.bump == 'patch' && 'pypi-auto' || 'pypi' }}"
- name: Checkout main
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
ref: main
fetch-depth: 0
token: ${{ secrets.GH_TOKEN }}
- name: Set up Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: '3.11'
- name: Set up uv
uses: astral-sh/setup-uv@38f3f104447c67c051c4a08e39b64a148898af3a # v4
- name: Configure git
run: |
git config user.name "MervinPraison"
git config user.email "[email protected]"
gh auth setup-git
- name: Compute release version
id: versions
env:
BUMP: ${{ inputs.bump }}
VERSION_OVERRIDE: ${{ inputs.version }}
run: |
python <<'PY'
import os
import re
import sys
from pathlib import Path
SEMVER = re.compile(r"^\d+\.\d+\.\d+$")
bump = os.environ["BUMP"]
override = os.environ.get("VERSION_OVERRIDE", "").strip()
def bump_version(version: str) -> str:
parts = version.split(".")
if len(parts) != 3:
print(f"Invalid version: {version}", file=sys.stderr)
sys.exit(1)
maj, min_, patch = (int(parts[0]), int(parts[1]), int(parts[2]))
if bump == "major":
return f"{maj + 1}.0.0"
if bump == "minor":
return f"{maj}.{min_ + 1}.0"
return f"{maj}.{min_}.{patch + 1}"
pyproject = Path("pyproject.toml")
content = pyproject.read_text()
match = re.search(r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE)
if not match:
print("Could not read version from pyproject.toml", file=sys.stderr)
sys.exit(1)
current = match.group(1)
if not SEMVER.match(current):
print(f"Invalid current version: {current}", file=sys.stderr)
sys.exit(1)
if override:
if not SEMVER.match(override):
print(f"Invalid version override: {override}", file=sys.stderr)
sys.exit(1)
new_version = override
else:
new_version = bump_version(current)
with open(os.environ["GITHUB_OUTPUT"], "a", encoding="utf-8") as fh:
fh.write(f"current_version={current}\n")
fh.write(f"new_version={new_version}\n")
print(f"aiui: {current} -> {new_version}")
PY
- name: Dry run summary
if: inputs.dry_run
run: |
echo "Dry run — no publish, commit, or push."
echo "Package: ${{ env.PACKAGE }}"
echo "Version: ${{ steps.versions.outputs.current_version }} -> ${{ steps.versions.outputs.new_version }}"
echo "Would: bump pyproject.toml + __version__.py, uv publish, commit, tag, GitHub release"
- name: Bump version files
if: inputs.dry_run != true
env:
CURRENT: ${{ steps.versions.outputs.current_version }}
NEW_VERSION: ${{ steps.versions.outputs.new_version }}
run: |
set -euo pipefail
python <<'PY'
import os
import re
from pathlib import Path
current = os.environ["CURRENT"]
new = os.environ["NEW_VERSION"]
pyproject = Path("pyproject.toml")
content = pyproject.read_text()
pyproject.write_text(content.replace(f'version = "{current}"', f'version = "{new}"', 1))
version_py = Path("src/praisonaiui/__version__.py")
vcontent = version_py.read_text()
version_py.write_text(re.sub(
r'__version__ = "[^"]+"',
f'__version__ = "{new}"',
vcontent,
count=1,
))
PY
- name: Publish aiui to PyPI
if: inputs.dry_run != true
run: |
set -euo pipefail
rm -rf dist
uv lock
uv build
uv publish
- name: Wait for aiui on PyPI
if: inputs.dry_run != true
run: |
set -euo pipefail
VERSION="${{ steps.versions.outputs.new_version }}"
MAX_WAIT=600
INTERVAL=30
START=$(date +%s)
while true; do
if curl -fsSL "https://pypi.org/pypi/${PACKAGE}/${VERSION}/json" >/dev/null; then
echo "✅ ${PACKAGE}==${VERSION} is available on PyPI"
exit 0
fi
ELAPSED=$(( $(date +%s) - START ))
if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then
echo "❌ Timeout waiting for ${PACKAGE}==${VERSION} on PyPI"
exit 1
fi
echo "⏳ Waiting for ${PACKAGE}==${VERSION} ($(( MAX_WAIT - ELAPSED ))s remaining...)"
sleep "$INTERVAL"
done
- name: Commit, tag, and release
if: inputs.dry_run != true
env:
VERSION: ${{ steps.versions.outputs.new_version }}
run: |
set -euo pipefail
TAG="v${VERSION}"
git add pyproject.toml uv.lock src/praisonaiui/__version__.py
git diff --cached --quiet && { echo "No version files to commit"; exit 0; }
git commit -m "Release ${TAG}"
git tag -f "${TAG}"
git pull --rebase origin main
git tag -f "${TAG}"
git push origin main
git push --tags -f
gh release create "${TAG}" \
--title "PraisonAIUI ${TAG}" \
--notes "Release ${TAG}" \
--latest
- name: Verify release
if: inputs.dry_run != true
run: echo "✅ ${{ env.PACKAGE }}==${{ steps.versions.outputs.new_version }}"
@@ -0,0 +1,33 @@
name: Sync Claude Secrets from PraisonAI
# GitHub does not allow reading secret values back via API.
# This workflow triggers the sync job in MervinPraison/PraisonAI, which copies:
# CLAUDE_APP_ID, CLAUDE_APP_PRIVATE_KEY, CLAUDE_CODE_OAUTH_TOKEN, GH_TOKEN
#
# Requires SECRETS_ADMIN_PAT in PraisonAI (repo Settings → Secrets).
# If sync fails, copy secrets manually:
# PraisonAI → Settings → Secrets → Actions
# PraisonAIUI → Settings → Secrets → Actions (same names)
on:
workflow_dispatch:
permissions:
contents: read
jobs:
trigger-sync:
runs-on: ubuntu-latest
steps:
- name: Trigger PraisonAI secret sync
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh workflow run sync-secrets-to-aiui.yml \
--repo MervinPraison/PraisonAI \
--ref main \
-f target_repo=MervinPraison/PraisonAIUI
echo "Triggered: https://github.com/MervinPraison/PraisonAI/actions/workflows/sync-secrets-to-aiui.yml"
echo ""
echo "If sync fails (401/403), refresh SECRETS_ADMIN_PAT in PraisonAI,"
echo "or copy CLAUDE_APP_ID + CLAUDE_APP_PRIVATE_KEY + GH_TOKEN manually."
+60
View File
@@ -0,0 +1,60 @@
# Python
__pycache__/
*.py[cod]
*$py.class
.venv/
venv/
env/
build/
dist/
*.egg-info/
.pytest_cache/
.coverage
coverage.xml
htmlcov/
.mypy_cache/
.ruff_cache/
# JavaScript / Node
node_modules/
.next/
dist/
.npm/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-lock.yaml
*.tsbuildinfo
# Environment
.env
.env.local
.env.*.local
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Project specific
aiui/
*.log
*.err
.praison/
.gemini/
.internal/
# Generated
site/
docs/_build/
aiui-output/
_site
.praisonai
tmp/
*.db
@@ -0,0 +1,375 @@
---
description: Comprehensive analysis workflow that produces a detailed GitHub issue — combines deep codebase analysis with issue creation for implementation-ready tickets
---
# Analysis → GitHub Issue Workflow
Deep Analysis → Gap Analysis → Critical Review → Plan → Create GitHub Issue.
> **When to use this:** You need to analyze a feature, integration, or system deeply and produce a GitHub issue that another agent/developer can implement immediately without asking follow-up questions.
> **When NOT to use this:** Use `/analysis` for analysis-only (no issue). Use `/local-fix` if you're implementing yourself.
---
## PRINCIPLES (apply throughout)
- **Agent-centric**: Agents, workflows, sessions, tools, memory, multi-agent safety.
- **Protocol-driven core**: praisonaiagents = lightweight, protocol-first (protocols/hooks/adapters only).
- **DRY**: identify reuse; avoid duplication.
- **No perf impact**: preserve import-time and hot-path; heavy deps optional + lazy.
- **Async-safe + multi-agent safe** by default.
- **Easy for non-developers**: "Few lines of code to do the task!"
- **No competitor names in public surfaces**: Never mention competitor product, company, or project names in GitHub issues, PRs, commit messages, release notes, docs, or any other public-facing content. Refer to capabilities generically (e.g., "self-improving agent pattern", "external agent framework").
---
## CANONICAL PATHS
```
UI Repo: /Users/praison/praisonaiui (praisonaiui)
SDK Core: /Users/praison/praisonai-package/src/praisonai-agents (praisonaiagents)
Docs: /Users/praison/PraisonAIDocs
Extension: src/praisonaiui/*, docs/*, tests/*
```
---
## Phase 1 — Acceptance Criteria
Translate the request into testable criteria:
- API expectations (classes, methods, signatures)
- CLI expectations (commands, flags, help text)
- Documentation expectations (pages, examples)
- Test expectations (unit, integration, smoke, real agentic)
- Performance constraints (import time, hot-path)
---
## Phase 2 — External Research (if applicable)
### 2a. Read official sources
If analyzing an external integration, research from primary sources:
```bash
# Use read_url_content tool for:
# - Official site / announcement pages
# - GitHub README and docs
# - Framework documentation
# - Third-party write-ups
```
**Capture:**
- What is it? Purpose and design goals
- Key terminology and concepts
- Architecture overview
- Current ecosystem state
- References list (all URLs)
### 2b. Clone & analyze external codebase (if applicable)
```bash
git clone <repo-url> ~/<repo-name> --depth=1
ls -la ~/<repo-name>/
```
Key files to read:
- `AGENTS.md` / `README.md` — architecture overview
- Base class files (abstract methods, signatures)
- Factory / registry files (registration pattern)
- Model/config files (data structures)
- Example implementations (minimal + full-featured)
- `pyproject.toml` / `package.json` — dependencies
---
## Phase 3 — PraisonAI Codebase Inventory
### 3a. Inventory with evidence
Go through ALL relevant files, understand current logic end-to-end.
```bash
# UI repo
ls /Users/praison/praisonaiui/src/praisonaiui/
ls /Users/praison/praisonaiui/tests/
ls /Users/praison/praisonaiui/docs/
# Optional cross-check against SDK only when needed
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/
```
**Document:**
- Public APIs: modules/classes/functions and exports
- Protocols/adapters/hooks and extension points
- CLI commands, options, help text
- Integrations (db/observability/tools)
- Tests (unit/integration), fixtures, CI config
- Docs (Mintlify), examples, recipes
Provide: **file paths + key symbols + grep counts + entry points**.
### 3b. Identify DRY opportunities
- Existing abstractions that can be reused
- Duplicated code that should be consolidated
- Existing protocols before creating new ones
---
## Phase 4 — Detailed Analysis
### 4a. Architecture and behavior
- Control flow and data flow
- Concurrency model (sync/async)
- Multi-agent interactions
- Dependency boundaries (core/wrapper/tools)
- Failure modes and error handling
### 4b. Invariants check
Verify these are preserved:
- [ ] Protocol-driven core (no heavy impls in praisonaiagents)
- [ ] Lazy imports (optional deps never at module level)
- [ ] Backward compatible (public API changes need deprecation)
- [ ] Safe defaults (new features opt-in)
---
## Phase 5 — Gap Analysis
Compare acceptance criteria vs current state.
### Checklist
| Area | Current State | Gap | Severity | Impact | Placement |
|------|---------------|-----|----------|--------|-----------|
| Core SDK | | | | | |
| Wrapper | | | | | |
| Tools/plugins | | | | | |
| CLI | | | | | |
| Docs | | | | | |
| Tests | | | | | |
| Exports | | | | | |
| Perf | | | | | |
| Multi-agent + async | | | | | |
### Gap severity levels
- **Critical**: Blocks functionality
- **High**: Significant limitation
- **Medium**: Missing feature
- **Low**: Nice-to-have
---
## Phase 6 — Critical Review
### 6a. Risks and footguns
- API ambiguity or edge cases
- Backward compatibility concerns
- Coupling violations
- Performance regressions
- Concurrency hazards
- Misuse risks
- Operational concerns
### 6b. Mitigation strategies
For each risk, document:
- "Safe by default" recommendation
- Explicit opt-in for dangerous behavior
- Documentation warnings
---
## Phase 7 — Implementation Plan
Step-by-step plan (DO NOT implement):
### 7a. Test-first (TDD)
1. Unit tests for new functionality
2. Integration tests for cross-component behavior
3. Smoke tests for quick validation
4. **Real agentic tests** (REQUIRED):
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are helpful")
result = agent.start("Say hello in one sentence")
print(result) # Must call LLM and produce response
```
### 7b. Implementation order
1. Tests (TDD)
2. Core implementation
3. CLI integration
4. Documentation
5. Verification
### 7c. Files to change/create
| File | Action | Purpose |
|------|--------|---------|
| | | |
### 7d. Verification commands
```bash
# Unit tests
pytest tests/unit/test_<feature>.py -v
# Integration tests
pytest tests/integration/test_<feature>.py -v
# Smoke test
python -c "from praisonaiagents import <Feature>; print('OK')"
# Real agentic test
python examples/<feature>_example.py
```
---
## Phase 8 — Draft GitHub Issue
The issue must be **self-contained**. Another agent must be able to implement by reading only the issue.
### Required sections
```markdown
## Overview
One paragraph: what, why, and the end goal.
## Background
- Purpose and design goals
- Why this is valuable
- Current state / ecosystem
## Architecture Analysis
### Current Implementation
- Key files and their purposes
- Integration points
- Data flow
### Key File Locations
| File | Purpose | Lines |
|------|---------|-------|
## Gap Analysis Summary
### Critical Gaps
| Gap | Impact | Effort |
|-----|--------|--------|
### Feature Gaps
| Feature | Current Support | Gap |
|---------|-----------------|-----|
## Proposed Implementation
### Phase 1: Minimal
Working code example.
### Phase 2: Production
Working code example.
## Files to Create / Modify
### New files
| File | Purpose |
|------|---------|
### Modified files
| File | Change |
|------|--------|
## Technical Considerations
- Dependencies
- Performance impact
- Safety / approval
- Multi-agent safety
## Acceptance Criteria
- [ ] Verifiable checkbox list
## Implementation Notes
### Key Files to Read First
1. `path/to/file.py` (N lines) — purpose
### Critical Integration Points
1. Where X connects to Y
### Testing Commands
```bash
# Copy-pastable commands
```
## References
- [Link](url)
```
---
## Phase 9 — Create GitHub Issue
### 9a. Create via `gh` CLI
```bash
gh issue create \
--repo MervinPraison/PraisonAIUI \
--title "<Type>: <Descriptive Title>" \
--body "<issue body>"
```
**Title formats:**
- `Feature: <What>` — new functionality
- `Analysis: <Topic>` — analysis/research
- `Integration: <External System>` — external integration
- `Fix: <Problem>` — bug fix proposal
### 9b. Verify issue created
```bash
gh issue view <number> --repo MervinPraison/PraisonAIUI | head -20
```
---
## Checklist — Before Creating Issue
- [ ] Acceptance criteria defined and testable
- [ ] All relevant PraisonAI files read (not skimmed)
- [ ] External sources researched (if applicable)
- [ ] Gap analysis completed with severity ratings
- [ ] Critical review identifies risks and mitigations
- [ ] Implementation plan is step-by-step with file list
- [ ] Issue body has working code examples (not pseudocode)
- [ ] All file paths are absolute and verified
- [ ] CLI commands are copy-pastable
- [ ] Acceptance criteria are verifiable (not vague)
- [ ] References section includes all URLs
- [ ] Issue is self-contained — no "see docs" without details
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---------|-----|
| Pseudocode in examples | Use real, runnable code with imports |
| Vague file paths | Use absolute paths |
| Skipping gap analysis | Every gap needs severity + impact |
| Missing real agentic test | Include `agent.start()` test, not just construction |
| No verification commands | Include copy-pastable pytest/python commands |
| Claiming "done" without evidence | Every claim references specific files/symbols |
| Implementing instead of analyzing | This workflow produces issues, not code |
---
## Hard Rules
1. **DO NOT implement** — this workflow produces analysis and issues only
2. **DO NOT claim done** without evidence
3. **Every claim must reference** specific files/symbols
4. **Issue must be self-contained** — implementer needs no follow-up questions
5. **Working code examples required** — no pseudocode
+104
View File
@@ -0,0 +1,104 @@
---
description: analysis
---
You are an expert AI engineer in the PraisonAI ecosystem.
Your job: produce ONLY (1) analysis, (2) review, (3) gap analysis, (4) critical review, (5) plan, (6) proposal.
Do NOT implement. Do NOT write code. Do NOT update docs. Do NOT run tests beyond discovery.
Be precise, evidence-based, and agent-centric.
PRINCIPLES (apply in all analysis/proposals):
- Agent-centric: Agents, workflows, sessions, tools, memory, multi-agent safety.
- Protocol-driven core: praisonaiagents = lightweight, protocol-first (protocols/hooks/adapters only).
- DRY: identify reuse; avoid duplication.
- No perf impact: preserve import-time and hot-path; heavy deps optional + lazy.
- Async-safe + multi-agent safe by default.
- Clear paid upgrade path (support/cloud/services) without restricting core.
- Easy for non-developers. "Few lines of code to do the task!"
CANONICAL PATHS:
- UI Repo: /Users/praison/praisonaiui (praisonaiui)
- SDK Core (reference): /Users/praison/praisonai-package/src/praisonai-agents (praisonaiagents)
- Docs: /Users/praison/PraisonAIDocs (JS: docs/js, Rust: docs/rust)
- Extension points: src/praisonaiui/*, docs/*, tests/*
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MANDATORY PROCESS (NO IMPLEMENTATION)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
STEP 1 — Acceptance Criteria
- Translate request into testable criteria: API, CLI, docs, test expectations, perf constraints.
STEP 2 — Repo Inventory (evidence-based)
- Go through ALL relevant files, understand current logic end-to-end.
- Inventory with evidence:
- Public APIs: modules/classes/functions and exports
- Protocols/adapters/hooks and extension points
- CLI commands, options, help text
- Integrations (db/observability/tools)
- Tests (unit/integration), fixtures, CI config
- Docs (Mintlify), examples, recipes
- Provide: file paths + key symbols + grep counts + entry points.
- Identify DRY opportunities.
STEP 3 — Detailed Analysis
- Architecture and behavior: control flow, data flow, concurrency (sync/async), multi-agent interactions, dependency boundaries (core/wrapper/tools), failure modes.
- Highlight invariants: protocol-driven core, lazy imports, optional deps.
STEP 4 — Detailed Review
- Evaluate against principles: agent-centricity, API simplicity, DRY, perf, optional deps + lazy imports, async/multi-agent safety, test coverage, CLI parity, docs clarity.
- Concrete evidence for each judgment.
STEP 5 — Gap Analysis
- Compare acceptance criteria vs current state. Checklist:
- UI Core, CLI, Docs, Tests, Exports, Perf, Multi-agent + async
- Each gap: severity, impact, risk, recommended location (core/wrapper/tools).
STEP 6 — Critical Review
- Risks, footguns, maintenance concerns:
- API ambiguity, edge cases, backward compat
- Coupling violations, perf regressions, concurrency hazards
- Misuse risks, operational concerns
- Mitigation strategies and "safe by default" recommendations.
STEP 7 — Plan
- Step-by-step (do not implement): tests (TDD) → implementation → CLI → docs → verification
- Exact files to change/create. Migration/compat plan. Rollback plan. Verification commands. Perf checks. Multi-agent + async test strategy.
REAL AGENTIC TEST definition (MUST include in every verification plan):
- A "real agentic test" = agent ACTUALLY RUNS and calls the LLM:
1. Create Agent with the feature being tested
2. Call `agent.start("a real task prompt")` — NOT just constructing the object
3. Agent MUST call LLM and produce text response
4. Print full output so dev can see it worked end-to-end
- Example:
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are a helpful assistant")
result = agent.start("Say hello in one sentence")
print(result)
```
- Assert-only object construction = SMOKE TEST, not real agentic test.
- Both smoke AND real agentic tests required.
STEP 8 — Proposal
- Minimal, agent-centric design and API/CLI surface:
- protocols/hooks in core; implementations in wrapper/tools
- Clear defaults and explicit overrides
- Multi-agent resource isolation/sharing
- Error model and observability hooks
- Include: "Simple API" examples, CLI UX, docs outline, paid upgrade path.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
REQUIRED OUTPUT (in order):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1) Acceptance Criteria
2) Inventory (evidence: paths/symbols/exports/grep counts)
3) Detailed Analysis (architecture + flows + invariants)
4) Detailed Review (quality vs principles, evidence-based)
5) Gap Analysis (checklist + severity/impact/placement)
6) Critical Review (risks + mitigations)
7) Plan (step-by-step + file list + verification strategy)
8) Proposal (agent-centric design + API/CLI/docs outline)
Hard rules: DO NOT implement. DO NOT write code. DO NOT claim done. Every claim must reference specific files/symbols.
+228
View File
@@ -0,0 +1,228 @@
---
description: Audit existing docs against live code, then create a comprehensive GitHub issue in PraisonAIDocs with correct, tested information ready for a writer/agent to implement immediately
---
# Create PraisonAIDocs Issue Workflow
Audit code → Compare with existing docs → Draft correct content → Create issue.
> **When to use this:** A feature is already implemented in PraisonAI but the docs are missing, outdated, or wrong. You need to file a self-contained docs issue in `MervinPraison/PraisonAIDocs` that a writer or agent can act on without asking follow-up questions.
> **When NOT to use this:** Use `@[/create-github-issue]` for new integrations that need external research. Use `@[/local-fix]` if you are writing the docs yourself.
---
## Phase 1 — Identify the Feature & Existing Docs
### 1a. Find the relevant doc file
```bash
ls /Users/praison/PraisonAIDocs/docs/<section>/
cat /Users/praison/PraisonAIDocs/docs/<section>/<feature>.mdx
```
Key doc sections:
- `docs/observability/` — tracing providers (Langfuse, LangSmith, etc.)
- `docs/tools/` — tool integrations
- `docs/features/` — agent features
- `docs/cli/` — CLI commands
- `docs/guides/` — how-to guides
### 1b. Read the existing doc fully
Note every claim that needs verification:
- Install commands
- Import statements
- API method names and signatures
- Environment variable names
- CLI commands
---
## Phase 2 — Audit the Live Code
### 2a. Find the source implementation
```bash
# Search praisonaiagents core SDK
grep -rn "<feature>" /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/ 2>&1 | grep -v ".pyc"
# Search praisonai wrapper (CLI, integrations)
grep -rn "<feature>" /Users/praison/praisonai-package/src/praisonai/praisonai/ 2>&1 | grep -v ".pyc"
# Search praisonai-tools
grep -rn "<feature>" /Users/praison/PraisonAI-tools/ 2>&1 | grep -v ".pyc"
```
### 2b. Read all relevant source files end-to-end
Read every file that implements the feature. For each file capture:
- Actual class/function names and signatures
- Required vs optional parameters
- Environment variables read (exact names)
- What gets called internally (trace the call chain)
- Any version-specific behavior
Key files to always check:
| File pattern | What to look for |
|---|---|
| `praisonaiagents/obs/__init__.py` | `_LazyObsModule`, factory methods, `auto()` |
| `praisonai_tools/observability/providers/<name>_provider.py` | `init()`, `is_available()`, `shutdown()`, `flush()` |
| `praisonai/observability/<name>.py` | CLI sink adapter, event handling |
| `praisonai/cli/commands/<name>.py` | All CLI sub-commands and options |
| `praisonai/__init__.py` | Global env var overrides that may interfere |
### 2c. Test the feature live
Run minimal test scripts to verify the actual behavior:
```bash
# Test the import works
python3 -c "from praisonaiagents.obs import obs; provider = obs.<name>(); print(type(provider).__name__, provider._initialized)"
# Test CLI commands
praisonai <feature> --help
praisonai <feature> <subcommand>
# Verify traces/output appear
timeout 30 praisonai <feature> <subcommand> --limit 5
```
### 2d. Build a "What's Wrong" table
For each doc claim that is incorrect, record:
| Current Doc (Wrong) | Correct |
|---|---|
| wrong install command | correct install |
| wrong import | correct import |
| non-existent method | actual method |
| wrong env var name | actual env var |
---
## Phase 3 — Draft the Issue
The issue body must be **self-contained and implementation-ready**. A writer should be able to update the doc by reading only the issue — no follow-up questions.
### Required sections:
```markdown
## Overview
One paragraph: what doc file needs updating, why it's wrong, and the end goal.
State explicitly: "All code in this issue has been tested and verified working."
## What's Wrong With the Current Docs
Table: Current (Wrong) | Correct
Cover: install commands, imports, API methods, env vars, missing sections.
## Correct Architecture (How It Actually Works)
Explain the actual internal call chain so the writer understands context.
Include a text diagram if helpful.
## Required Install
Exact pip commands, nothing more.
## Environment Variables
Table: Variable | Required | Description
Show bash export examples for both cloud and self-hosted.
## Python Usage
### Quickstart (Recommended)
Full working code with correct imports, init, agent run, and flush.
### Auto-Detection
Document obs.auto() or equivalent if applicable.
### Additional Patterns
Any other valid usage patterns (explicit provider, multi-agent, etc.).
## CLI Usage (if applicable)
All sub-commands with flags and examples.
Include an end-to-end CLI session example.
## Configuration File (if applicable)
Document any config files that are auto-created or auto-read.
## What Output Looks Like
Show what traces/output actually look like after a successful run.
## Version Compatibility Notes
Document any breaking changes between SDK versions that affect usage.
## Files to Update
Table: File | Change
## Acceptance Criteria
- [ ] Checkbox list — each item must be specific and verifiable
## References
List all source files read (with absolute paths).
```
---
## Phase 4 — Create the Issue
### 4a. Write body to a temp file
```bash
cat > /tmp/docs_issue_<feature>.md << 'EOF'
<issue body>
EOF
```
### 4b. Create via `gh` CLI
```bash
gh issue create \
--repo MervinPraison/PraisonAIDocs \
--title "Docs: <action verb> <feature> page — <one-line summary of what's wrong>" \
--label "documentation" \
--body-file /tmp/docs_issue_<feature>.md
```
**Title format:** `Docs: Rewrite/Update/Add <Feature> page — <what's wrong or missing>`
Examples:
- `Docs: Rewrite Langfuse integration page with correct Langfuse v4 API and CLI commands`
- `Docs: Add obs.auto() documentation to observability overview`
- `Docs: Fix LangSmith install command and update import paths`
### 4c. Verify
```bash
gh issue view <number> --repo MervinPraison/PraisonAIDocs | head -30
```
Confirm the URL: `https://github.com/MervinPraison/PraisonAIDocs/issues/<number>`
---
## Checklist — Before Creating the Issue
- [ ] Existing doc file read completely
- [ ] All source files implementing the feature read end-to-end (not skimmed)
- [ ] Feature tested live — not just code-read
- [ ] "What's Wrong" table is complete and specific
- [ ] All code examples in the issue are copy-pastable and tested
- [ ] All env var names are verified against source (not guessed)
- [ ] All CLI commands verified with `--help` and live run
- [ ] Acceptance criteria are specific and verifiable (not vague)
- [ ] References list includes all source file paths read
- [ ] Issue is self-contained — writer needs no follow-up
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---|---|
| Documenting what the code *should* do, not what it *does* | Run it. Test it. Document the actual behavior. |
| Copying import paths from docs being replaced | Always verify imports against source files |
| Missing the "What's Wrong" table | This is the most important section — be explicit |
| Vague acceptance criteria like "docs are updated" | Write specific, testable criteria: "install command is `pip install langfuse`" |
| Not checking for interfering globals (e.g. `OTEL_SDK_DISABLED`) | Always grep `__init__.py` files for env var overrides |
| Forgetting `provider.flush()` in examples | Async buffers need explicit flush before process exit |
| Not testing with a real API key | Code-reading alone misses runtime errors |
| Using `timeout` too short for first-run (downloads, auth) | Use `timeout 120` for agent runs, `timeout 30` for CLI |
+308
View File
@@ -0,0 +1,308 @@
---
description: Research a topic in-depth, analyze both external and local codebases, and create a comprehensive GitHub issue — ready for another agent/developer to act on immediately
---
# Create GitHub Issue Workflow
Research → Clone & Analyze → PraisonAI Analysis → Draft → Create Issue.
> **When to use this:** You need to create a detailed, implementation-ready GitHub issue for a new integration, feature, or benchmark. The issue must contain enough context that another agent or developer can implement it without asking further questions.
> **When NOT to use this:** Use `@[/local-fix]` if you are implementing the change yourself, not just filing an issue.
---
## Phase 1 — Online Research
### 1a. Read official sources
Research the topic from all primary sources: official site, GitHub repo, documentation, blog posts.
```bash
# Example searches (adapt to your topic)
# - Official site / announcement pages
# - GitHub README and docs
# - Third-party write-ups (e.g. Snorkel AI, Epoch AI)
# - Framework documentation (core concepts, agents, running)
```
URLs to read for each source (use `read_url_content` tool):
- Official announcement / news page
- GitHub repository README (multiple chunks if large)
- Framework/integration documentation pages
- Any relevant blog posts or analysis
**Capture for the issue:**
- What is it? Purpose and design goals
- Key terminology and concepts (with definitions)
- Architecture overview
- Current leaderboard / ecosystem state
- References list (all URLs)
### 1b. Read paginated content
For large pages, read additional chunks:
```
view_content_chunk(document_id=<url>, position=2)
view_content_chunk(document_id=<url>, position=3)
view_content_chunk(document_id=<url>, position=4)
```
Continue until all relevant sections are read (core concepts, agent types, running instructions, integration API).
---
## Phase 2 — Clone & Analyze External Codebase
### 2a. Clone the repository
```bash
git clone <repo-url> ~/<repo-name> --depth=1
```
### 2b. Explore structure
```bash
ls -la ~/<repo-name>/
ls -la ~/<repo-name>/src/
```
Key files to read (adapt paths to repo):
- `AGENTS.md` / `CLAUDE.md` / `README.md` — architecture overview
- Base class files (e.g. `base.py` for agents, environments)
- Factory / registry files (how things are registered)
- Model/config files (data structures agents must populate)
- Enum files (valid names, types)
- Example agent implementations (minimal + full-featured)
- `pyproject.toml` — Python version, dependencies
**Capture for the issue:**
- Repository structure diagram
- Key file paths with line counts
- Base class interface (all abstract methods with signatures)
- How to register a new agent (enum + factory pattern)
- Data models the agent must populate (`AgentContext`, etc.)
- Example agent implementations (minimal and production)
- CLI commands to run the integration
- Environment variables required
### 2c. Read base classes end-to-end
Read every relevant base class completely. For agent integrations:
```
read_file(base.py) # BaseAgent / BaseInstalledAgent
read_file(factory.py) # AgentFactory registration
read_file(models/agent/name.py) # AgentName enum
read_file(models/agent/context.py) # AgentContext fields
read_file(examples/agents/minimal_agent.py) # Minimal example
read_file(agents/installed/reference_agent.py) # Full example
```
### 2d. Read a reference implementation
Pick the most complete existing agent implementation (e.g. `codex.py`, `gemini_cli.py`) and read it fully. This reveals:
- Install pattern (system packages → user packages)
- Version detection (`get_version_command` / `parse_version`)
- `@with_prompt_template` decorator usage
- `populate_context_post_run` for token tracking
- ATIF trajectory support (`SUPPORTS_ATIF`)
- `CliFlag` / `EnvVar` declarative config
- `exec_as_root` vs `exec_as_agent` usage
---
## Phase 3 — Analyze PraisonAI Codebase
### 3a. Identify relevant components
```bash
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/tools/
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/agent/
```
Key files to read for agent integration issues:
| File | What to look for |
|------|-----------------|
| `praisonaiagents/tools/shell_tools.py` | `execute_command`, approval decorators |
| `praisonaiagents/agent/agent.py` | `Agent.start()`, `Agent.chat()`, token tracking |
| `praisonaiagents/approval/` | `@require_approval`, auto-approval backend |
| `praisonaiagents/eval/` | Evaluation framework hooks |
| `praisonaiagents/agents/agents.py` | `AgentTeam` multi-agent |
| `pyproject.toml` | Current version, optional dependencies |
### 3b. Map integration points
For each PraisonAI component, document:
- What it does
- How it maps to the external system's interface
- What needs bridging (e.g. wrapping `environment.exec()` as a tool)
- Known gotchas (e.g. `@require_approval` must be bypassed in containers)
---
## Phase 4 — Draft the Issue
The issue body must be self-contained. Another agent must be able to implement the feature by reading only the issue — no follow-up questions.
### Required sections:
```markdown
## Overview
One paragraph: what, why, and the end goal.
## Background: What is <X>?
- Purpose and design goals
- Key statistics (task count, solve rates, etc.)
- Why <X> + PraisonAI is valuable
- Current ecosystem / leaderboard state
## <X> Architecture (Codebase Analysis)
> Repo analyzed locally: `~/<repo-name>` (cloned at `~/<repo-name>`)
### Core Concepts
Table: Concept | Description
### Two (or N) Integration Types
Code examples for each type with full signatures.
### Key File Locations in <X> Codebase
Directory tree with annotations for each important file.
### Data Models
Full class definitions the agent must populate.
### How to Run (CLI)
All relevant CLI commands with flags and examples.
## PraisonAI Architecture (Relevant to This Integration)
Table: Component | Location | Relevance
### PraisonAI Execution Model
How PraisonAI currently handles the relevant operations, and what must be adapted.
## Proposed Implementation Plan
### Approach: <Recommended> (with justification)
### Phase 1: Minimal Proof-of-Concept
Full working code example.
### Phase 2: Production Implementation
Full working code example.
### Phase N: Advanced Features
(ATIF, multi-agent, etc.)
## Files to Create / Modify
### New files (praisonai-package)
Table: File | Purpose
### Modifications to <External Repo> (PR upstream)
Table: File | Change
## Technical Considerations
Subsections for:
- Container/environment dependencies
- API key forwarding
- Safety/approval bypass
- Token tracking
- Parallel execution safety
## Job / Config Example
Working YAML config + CLI invocation.
## Use Cases Unlocked
Table: Use Case | How
## Acceptance Criteria
- [ ] Checkbox list of verifiable outcomes
## Implementation Notes for the Assigned Agent/Developer
### Key <X> Files to Read First
Numbered list with file paths and line counts.
### Key PraisonAI Files to Read
Numbered list with file paths.
### Critical Integration Points
Numbered list of the exact code-level bridges needed.
### Architecture Decision
Why the chosen approach (installed vs external, etc.) with trade-offs.
### Installation & Testing Commands
Copy-pastable commands to install, verify, and run.
### Upstream PR
What to submit upstream and where.
## References
Bullet list of all URLs used.
```
---
## Phase 5 — Create the Issue
### 5a. Create via `gh` CLI
```bash
gh issue create \
--repo <org>/<repo> \
--title "Feature: <Descriptive Title>" \
--label "enhancement" \
--body "<issue body>"
```
**Title format:** `Feature: <What> with <Integration> (<Framework/Version>)`
Example:
```bash
gh issue create \
--repo MervinPraison/PraisonAI \
--title "Feature: Integrate PraisonAI Agents with Terminal-Bench 2.0 (Harbor Framework)" \
--label "enhancement" \
--body "..."
```
### 5b. Verify the issue was created
```bash
gh issue view <issue-number> --repo <org>/<repo> | head -20
```
The output URL confirms success: `https://github.com/<org>/<repo>/issues/<number>`
---
## Checklist — Before Creating the Issue
- [ ] All primary documentation URLs read (including paginated chunks)
- [ ] External repo cloned locally and analyzed
- [ ] Base classes read end-to-end (not just skimmed)
- [ ] At least one reference implementation read fully
- [ ] PraisonAI codebase analyzed for integration points
- [ ] Issue body has working code examples (not pseudocode)
- [ ] All file paths are absolute and verified to exist
- [ ] CLI commands are copy-pastable and complete
- [ ] Acceptance criteria are verifiable (not vague)
- [ ] References section includes all URLs used
- [ ] Issue is self-contained — no "see docs for details" without the details
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---------|-----|
| Pseudocode in examples | Use real, runnable code with imports |
| Vague file paths like `agents/` | Use absolute paths like `~/harbor/src/harbor/agents/base.py` |
| Missing `--depth=1` on clone | Large repos take forever; always use shallow clone |
| Only reading chunk 0 of a URL | Read chunks 1–4+ for paginated content |
| Skipping the factory/registry file | This is where registration happens; always read it |
| Not reading a reference agent | Pattern is not obvious from base class alone |
| Forgetting API key forwarding section | Always document how secrets are passed to containers |
| Skipping `populate_context_post_run` | Harbor uses this for token tracking and leaderboard data |
| Missing upstream PR instructions | Specify exact files to modify upstream for first-class support |
+190
View File
@@ -0,0 +1,190 @@
---
description: create and publish a post on mer.vin using praisonaiwp
---
## Config
- Server: `default` → `https://mer.vin`
- Config: `~/.praisonaiwp/config.yaml`
- Category for PraisonAI features: `PraisonAI`
---
## Step 1 — Compose the content
Structure every post as:
1. **Intro paragraph** — one sentence, what the feature solves
2. **Mermaid diagram** — architecture/flow (see block format below)
3. **Sections** — H2 headings, tables > prose, code blocks for usage
4. **Performance/summary** — table with concrete numbers
Keep it technical. Lead with diagrams and tables, not paragraphs.
---
## Step 2 — Mermaid block format (merpress)
> **Creating merpress:** Install the [Merpress – Mermaid for WordPress](https://wordpress.org/plugins/merpress/) plugin via `wp plugin install merpress --activate --allow-root` on the server. It adds the `wp:merpress/mermaidjs` block used below.
All posts use the native `wp:merpress/mermaidjs` block. Use this exact format:
```
<!-- wp:merpress/mermaidjs {"align":"full"} -->
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid alignfull"><pre class="mermaid">%%{init: {"theme": "base", "themeVariables": {"background": "transparent", "lineColor": "#000000"}}}%%
graph TD
A[Input] --> B[Agent]
B --> C[Tool]
C --> D[Output]
classDef hook fill:#189AB4,color:#fff
classDef agent fill:#8B0000,color:#fff
classDef decision fill:#444,color:#fff
class B agent
class C hook
</pre></div>
<!-- /wp:merpress/mermaidjs -->
```
**Do NOT use:** `[mermaid]...[/mermaid]` shortcode — that is the wrong format.
Color scheme:
- `#8B0000` (dark red) — agents, inputs, outputs
- `#189AB4` (teal) — tools, hooks
- `#444` — decisions/conditionals
---
## Step 2a — SVG/image upload via SSH
`praisonaiwp media upload` correctly SFTPs the file to `/tmp/` on the server, but
`_execute_wp()` in `~/praisonaiwp-cli/praisonaiwp/core/wp_client.py` never appends
`--allow-root`. Use direct SSH instead.
**SVG upload (Safe SVG plugin active on mer.vin):**
```bash
# 1. SCP SVG to server
scp -i ~/.ssh/id_ed25519 /path/to/diagram.svg <SSH_USER>@<SERVER_IP>:/tmp/
# 2. Import via WP-CLI — must pass --user=<admin> so Safe SVG capability check passes
ssh -i ~/.ssh/id_ed25519 <SSH_USER>@<SERVER_IP> \
"cd <WP_ROOT> && \
wp media import /tmp/diagram.svg --post_id=<POST_ID> \
--title='Title' --alt='Alt' --user=praison --allow-root --porcelain"
# → returns media ID
# 3. Get the URL
ssh -i ~/.ssh/id_ed25519 <SSH_USER>@<SERVER_IP> \
"cd <WP_ROOT> && \
wp post get <MEDIA_ID> --field=guid --allow-root"
```
> **Key:** `--user=praison` is required — Safe SVG checks upload capability against the
> current WP user. Without it, even with the plugin active, SVG imports are blocked.
**PNG fallback (if Safe SVG not available):**
```bash
rsvg-convert -w 1360 /path/to/diagram.svg -o /tmp/diagram_2x.png
# Then follow the same SSH steps above using the .png file (no --user needed)
```
Use this Gutenberg image block in the post content:
```
<!-- wp:image {"id":<MEDIA_ID>,"sizeSlug":"full","linkDestination":"none"} -->
<figure class="wp-block-image size-full"><img src="<IMAGE_URL>" alt="Alt text" class="wp-image-<MEDIA_ID>"/></figure>
<!-- /wp:image -->
```
---
## Step 3 — Create the post
```bash
praisonaiwp create "Post Title" \
--status publish \
--content '<FULL GUTENBERG CONTENT>'
```
Note the returned **Post ID** from the output.
---
## Step 4 — Set category
```bash
praisonaiwp update <POST_ID> --category "PraisonAI"
```
---
## Step 5 — Validate mermaid format
```bash
ssh -i ~/.ssh/id_ed25519 <SSH_USER>@<SERVER_IP> \
"cd <WP_ROOT> && \
wp post get <POST_ID> --field=post_content --allow-root | grep -i mermaid"
```
Expected output must contain `wp:merpress/mermaidjs`, not `[mermaid]`.
---
## Key Gutenberg blocks reference
```
<!-- wp:paragraph --><p>text</p><!-- /wp:paragraph -->
<!-- wp:heading --><h2 class="wp-block-heading">Title</h2><!-- /wp:heading -->
<!-- wp:heading {"level":3} --><h3 class="wp-block-heading">Sub</h3><!-- /wp:heading -->
<!-- wp:code --><pre class="wp-block-code"><code>code here</code></pre><!-- /wp:code -->
<!-- wp:table -->
<figure class="wp-block-table"><table>
<thead><tr><th>Col</th></tr></thead>
<tbody><tr><td>Val</td></tr></tbody>
</table></figure>
<!-- /wp:table -->
<!-- wp:list --><ul class="wp-block-list"><li>item</li></ul><!-- /wp:list -->
<!-- wp:separator --><hr class="wp-block-separator has-alpha-channel-opacity"/><!-- /wp:separator -->
```
---
## Full example command
```bash
praisonaiwp create "Feature Name: What It Does" \
--status publish \
--content '<!-- wp:paragraph -->
<p>One sentence intro.</p>
<!-- /wp:paragraph -->
<!-- wp:heading -->
<h2 class="wp-block-heading">Architecture</h2>
<!-- /wp:heading -->
<!-- wp:merpress/mermaidjs {"align":"full"} -->
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid alignfull"><pre class="mermaid">%%{init: {"theme": "base", "themeVariables": {"background": "transparent", "lineColor": "#000000"}}}%%
graph TD
A[Start] --> B[Agent]
class B agent
classDef agent fill:#8B0000,color:#fff
</pre></div>
<!-- /wp:merpress/mermaidjs -->
<!-- wp:code -->
<pre class="wp-block-code"><code>from praisonaiagents import Agent
agent = Agent(name="example")
result = agent.start("task")</code></pre>
<!-- /wp:code -->'
# Then set category:
praisonaiwp update <ID> --category "PraisonAI"
```
@@ -0,0 +1,677 @@
---
description: End-to-end workflow — deep analysis → GitHub issue → wait for implementing agents → create PR if missing → wait for reviewing agents → review PR locally → feedback to @claude → merge to main when robust per AGENTS.md
---
# End-to-End: Analysis → Issue → PR → Review → Merge
Deep Analysis → Gap Analysis → Critical Review → Plan → Create Issue → **Wait for implementing agents** → **Create PR if missing** → **Wait for reviewers** → **Validate PR locally** → **Feedback to @claude** → **Re-review after fixes** → **Merge to main if robust**.
> **When to use this:** You want a fully hands-off delivery loop. You describe a feature/integration/fix; this workflow produces the issue, monitors implementation by other agents (Claude, Copilot, CodeRabbit), validates their PR locally against `AGENTS.md` principles, loops feedback until the PR is robust, and merges to `main`.
> **When NOT to use this:** Use `/analysis-github-issue-create` if you only want the issue (no PR/merge). Use `/local-fix` if you are the implementer.
---
## PRINCIPLES (apply throughout)
- **Agent-centric**: Agents, workflows, sessions, tools, memory, multi-agent safety.
- **Protocol-driven core**: `praisonaiagents` = lightweight, protocol-first (protocols/hooks/adapters only).
- **DRY**: identify reuse; avoid duplication.
- **No perf impact**: preserve import-time and hot-path; heavy deps optional + lazy.
- **Async-safe + multi-agent safe** by default.
- **Easy for non-developers**: "Few lines of code to do the task!"
- **No competitor names in public surfaces**: Never mention competitor product, company, or project names in GitHub issues, PRs, commit messages, release notes, docs, or any other public-facing content. Refer to capabilities generically (e.g., "self-improving agent pattern", "external agent framework").
- **Test before merge**: never merge unvalidated PRs. Always clone the branch locally and run the tests.
- **Minimal code change**: prefer upstream one-line fixes over downstream workarounds.
- **Autonomous polling — NEVER ask the user to "check now"**: after posting feedback to `@claude`, submitting a trigger comment, or any state that requires an external agent to push commits, the assistant itself waits ~10 minutes (`sleep 600`) and then re-checks. Do not stop and wait for the human to type "check now". Only surface control back to the human when a round is fully complete (PR merged or 3-round feedback cap hit) or a blocking decision is required (e.g. rebase strategy, conflicting feature intent).
---
## CANONICAL PATHS
```
Core SDK: /Users/praison/praisonai-package/src/praisonai-agents (praisonaiagents)
Wrapper: /Users/praison/praisonai-package/src/praisonai (praisonai)
Tools: /Users/praison/PraisonAI-tools
Docs: /Users/praison/PraisonAIDocs
TypeScript: /Users/praison/praisonai-package/src/praisonai-ts
AGENTS.md: /Users/praison/praisonai-package/src/praisonai-agents/AGENTS.md
```
---
# PART A — ANALYSIS & ISSUE (Phases 1–9)
These phases are identical to `/analysis-github-issue-create`. Execute them in order. **Do not implement any code** in these phases — they produce analysis and an issue only.
## Phase 1 — Acceptance Criteria
Translate the request into testable criteria:
- API expectations (classes, methods, signatures)
- CLI expectations (commands, flags, help text)
- Documentation expectations (pages, examples)
- Test expectations (unit, integration, smoke, real agentic)
- Performance constraints (import time, hot-path)
---
## Phase 2 — External Research (if applicable)
### 2a. Read official sources
If analyzing an external integration, research from primary sources:
```bash
# Use read_url_content tool for:
# - Official site / announcement pages
# - GitHub README and docs
# - Framework documentation
# - Third-party write-ups
```
**Capture:**
- What is it? Purpose and design goals
- Key terminology and concepts
- Architecture overview
- Current ecosystem state
- References list (all URLs)
### 2b. Clone & analyze external codebase (if applicable)
```bash
git clone <repo-url> ~/<repo-name> --depth=1
ls -la ~/<repo-name>/
```
Key files to read:
- `AGENTS.md` / `README.md` — architecture overview
- Base class files (abstract methods, signatures)
- Factory / registry files (registration pattern)
- Model/config files (data structures)
- Example implementations (minimal + full-featured)
- `pyproject.toml` / `package.json` — dependencies
---
## Phase 3 — PraisonAI Codebase Inventory
### 3a. Inventory with evidence
Go through ALL relevant files, understand current logic end-to-end.
```bash
# Core SDK
ls /Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/
grep -r "class.*Protocol" praisonaiagents/ --include="*.py" | wc -l
# Wrapper
ls /Users/praison/praisonai-package/src/praisonai/praisonai/
ls /Users/praison/praisonai-package/src/praisonai/praisonai/cli/commands/
# TypeScript
ls /Users/praison/praisonai-package/src/praisonai-ts/src/
```
**Document:**
- Public APIs: modules/classes/functions and exports
- Protocols/adapters/hooks and extension points
- CLI commands, options, help text
- Integrations (db/observability/tools)
- Tests (unit/integration), fixtures, CI config
- Docs (Mintlify), examples, recipes
Provide: **file paths + key symbols + grep counts + entry points**.
### 3b. Identify DRY opportunities
- Existing abstractions that can be reused
- Duplicated code that should be consolidated
- Existing protocols before creating new ones
---
## Phase 4 — Detailed Analysis
### 4a. Architecture and behavior
- Control flow and data flow
- Concurrency model (sync/async)
- Multi-agent interactions
- Dependency boundaries (core/wrapper/tools)
- Failure modes and error handling
### 4b. Invariants check
Verify these are preserved:
- [ ] Protocol-driven core (no heavy impls in `praisonaiagents`)
- [ ] Lazy imports (optional deps never at module level)
- [ ] Backward compatible (public API changes need deprecation)
- [ ] Safe defaults (new features opt-in)
---
## Phase 5 — Gap Analysis
Compare acceptance criteria vs current state.
### Checklist
| Area | Current State | Gap | Severity | Impact | Placement |
|------|---------------|-----|----------|--------|-----------|
| Core SDK | | | | | |
| Wrapper | | | | | |
| Tools/plugins | | | | | |
| CLI | | | | | |
| Docs | | | | | |
| Tests | | | | | |
| Exports | | | | | |
| Perf | | | | | |
| Multi-agent + async | | | | | |
### Gap severity levels
- **Critical**: Blocks functionality
- **High**: Significant limitation
- **Medium**: Missing feature
- **Low**: Nice-to-have
---
## Phase 6 — Critical Review
### 6a. Risks and footguns
- API ambiguity or edge cases
- Backward compatibility concerns
- Coupling violations
- Performance regressions
- Concurrency hazards
- Misuse risks
- Operational concerns
### 6b. Mitigation strategies
For each risk, document:
- "Safe by default" recommendation
- Explicit opt-in for dangerous behavior
- Documentation warnings
---
## Phase 7 — Implementation Plan
Step-by-step plan (DO NOT implement):
### 7a. Test-first (TDD)
1. Unit tests for new functionality
2. Integration tests for cross-component behavior
3. Smoke tests for quick validation
4. **Real agentic tests** (REQUIRED):
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are helpful")
result = agent.start("Say hello in one sentence")
print(result) # Must call LLM and produce response
```
### 7b. Implementation order
1. Tests (TDD)
2. Core implementation
3. CLI integration
4. Documentation
5. Verification
### 7c. Files to change/create
| File | Action | Purpose |
|------|--------|---------|
| | | |
### 7d. Verification commands
```bash
# Unit tests
pytest tests/unit/test_<feature>.py -v
# Integration tests
pytest tests/integration/test_<feature>.py -v
# Smoke test
python -c "from praisonaiagents import <Feature>; print('OK')"
# Real agentic test
python examples/<feature>_example.py
```
---
## Phase 8 — Draft GitHub Issue
The issue must be **self-contained**. Another agent must be able to implement by reading only the issue.
### Required sections
```markdown
## Overview
One paragraph: what, why, and the end goal.
## Background
- Purpose and design goals
- Why this is valuable
- Current state / ecosystem
## Architecture Analysis
### Current Implementation
- Key files and their purposes
- Integration points
- Data flow
### Key File Locations
| File | Purpose | Lines |
|------|---------|-------|
## Gap Analysis Summary
### Critical Gaps
| Gap | Impact | Effort |
|-----|--------|--------|
### Feature Gaps
| Feature | Current Support | Gap |
|---------|-----------------|-----|
## Proposed Implementation
### Phase 1: Minimal
Working code example.
### Phase 2: Production
Working code example.
## Files to Create / Modify
### New files
| File | Purpose |
|------|---------|
### Modified files
| File | Change |
|------|--------|
## Technical Considerations
- Dependencies
- Performance impact
- Safety / approval
- Multi-agent safety
## Acceptance Criteria
- [ ] Verifiable checkbox list
## Implementation Notes
### Key Files to Read First
1. `path/to/file.py` (N lines) — purpose
### Critical Integration Points
1. Where X connects to Y
### Testing Commands
```bash
# Copy-pastable commands
```
## References
- [Link](url)
```
---
## Phase 9 — Create GitHub Issue
### 9a. Create via `gh` CLI
```bash
gh issue create \
--repo MervinPraison/PraisonAI \
--title "<Type>: <Descriptive Title>" \
--body-file /tmp/issue-body.md
```
**Title formats:**
- `Feature: <What>` — new functionality
- `Integration: <External System>` — external integration
- `Fix: <Problem>` — bug fix proposal
### 9b. Record the issue number
```bash
ISSUE_NUM=$(gh issue view <number> --repo MervinPraison/PraisonAI --json number --jq '.number')
echo "Tracking issue #$ISSUE_NUM"
```
---
# PART B — IMPLEMENTATION MONITORING (Phases 10–15)
After the issue is filed, other agents (`@claude`, GitHub Copilot agent, CodeRabbit) pick it up automatically. This part watches, shepherds, validates, and merges.
## Phase 10 — Wait ~10 min for implementing agents
After `gh issue create`, Claude and Copilot typically start work within seconds and finish a first pass in 5–15 minutes.
```bash
echo "Waiting 10 minutes for implementing agents..."
echo "Start: $(date)"
sleep 600
echo "End: $(date)"
```
### Then check: did they open a PR?
```bash
REPO=MervinPraison/PraisonAI
ISSUE_NUM=<number>
# Check for PRs that reference the issue
gh pr list --repo $REPO --state open --search "fixes #$ISSUE_NUM OR closes #$ISSUE_NUM" --json number,title,headRefName
# Also check for branches matching claude/issue-<N>-* naming convention
gh api repos/$REPO/branches --paginate --jq ".[] | select(.name | startswith(\"claude/issue-$ISSUE_NUM\")) | .name"
```
---
## Phase 11 — Create PR if none exists
If Claude pushed a branch but did not open a PR, open one yourself.
```bash
REPO=MervinPraison/PraisonAI
ISSUE_NUM=<number>
BRANCH=$(gh api repos/$REPO/branches --paginate --jq ".[] | select(.name | startswith(\"claude/issue-$ISSUE_NUM\")) | .name" | head -1)
if [ -n "$BRANCH" ]; then
TITLE=$(gh api repos/$REPO/commits/$BRANCH --jq '.commit.message' | head -1)
gh pr create --repo $REPO --head "$BRANCH" --base main \
--title "$TITLE" \
--body "Automated PR from Claude's work on issue #$ISSUE_NUM.
Branch: \`$BRANCH\`
Closes #$ISSUE_NUM"
fi
```
### If no branch exists after 10 minutes
Re-trigger Claude by commenting on the issue, then wait another 10 minutes and re-check:
```bash
gh issue comment $ISSUE_NUM --repo $REPO \
--body "@claude please pick up this issue — full analysis and plan are in the issue body."
sleep 600
```
---
## Phase 12 — Wait ~10 min for reviewing agents
Once a PR exists, `CodeRabbit`, `Copilot`, and CI pipelines run. Give them time to complete.
```bash
echo "Waiting 10 minutes for PR reviewers and CI..."
sleep 600
```
### Collect status
```bash
PR=<pr-number>
gh pr view $PR --repo $REPO --json state,mergeable,mergeStateStatus,updatedAt,commits,files \
| python -c "
import json,sys
d=json.load(sys.stdin)
print(f\" State: {d['state']} Mergeable: {d['mergeable']} MergeState: {d['mergeStateStatus']}\")
print(f\" Commits: {len(d['commits'])}\")
for f in d['files']:
print(f\" {f['path']}: +{f['additions']} -{f['deletions']}\")
"
# CI & review checks
gh pr view $PR --repo $REPO --json statusCheckRollup > /tmp/pr-checks.json
python -c "
import json
for c in json.load(open('/tmp/pr-checks.json'))['statusCheckRollup']:
s = c.get('conclusion') or c.get('status','?')
name = c.get('name') or c.get('context','?')
if s and s not in ('SKIPPED',):
print(f' {name}: {s}')
"
```
---
## Phase 13 — Validate the PR locally
**Never merge an unvalidated PR.** Always clone the branch and run tests.
```bash
REPO_URL=https://github.com/MervinPraison/PraisonAI.git
BRANCH=<branch-name>
WORKDIR=/tmp/pr-validate
rm -rf $WORKDIR
git clone --depth 1 --branch "$BRANCH" $REPO_URL $WORKDIR
cd $WORKDIR
# Files touched by the PR
gh pr view $PR --repo $REPO --json files --jq '.files[].path'
# Run the tests for changed files — ALWAYS use timeout (user global rule)
timeout 120 python -m pytest <test-paths> -v --tb=short
# Critical invariant checks (adapt per feature):
# 1) Lazy-import: heavy deps never imported at module level
timeout 30 python - <<'PY'
import sys
from praisonai.observability import <NewThing> # example
assert 'heavy_dep' not in sys.modules, "eager import — violates AGENTS.md §4.2"
print("OK: lazy import preserved")
PY
# 2) Cold-import benchmark (no regression)
timeout 30 python -c "import time; t=time.time(); import praisonaiagents; print(f'{(time.time()-t)*1000:.1f} ms')"
```
### Mergeability gate
A PR is **ready to merge only if ALL of these are true**:
- [ ] `gh pr view` reports `mergeable=MERGEABLE` and `mergeStateStatus` in `CLEAN`/`UNSTABLE` (not `DIRTY`/`BLOCKED`).
- [ ] All `test (3.x)` matrix jobs report `SUCCESS`.
- [ ] Local `pytest` on the changed test files passes with **zero failures** (skipped/xfailed tests are OK).
- [ ] Lazy-import invariant preserved (if the feature adds an optional dep).
- [ ] Cold-import time within ±2 % of `main` (AGENTS.md §4.2).
- [ ] No files outside the issue's declared scope were changed.
- [ ] The diff respects all invariants in AGENTS.md §4.6.
If **any** is false → go to Phase 14 (feedback). Do not merge.
---
## Phase 14 — Feedback to `@claude` when issues found
When validation fails, post a precise, actionable comment tagging `@claude`, referencing the exact test name, error, file, and the AGENTS.md principle violated.
```bash
gh pr comment $PR --repo $REPO --body "$(cat <<'EOF'
Hold on merge: validated locally on HEAD `<short-sha>` and found these issues:
**Test failures:**
```
FAILED tests/.../test_x.py::TestY::test_z
AssertionError: <actual-message>
```
**Root cause:** <one-line diagnosis referencing the exact file and line>.
**AGENTS.md violation(s):**
- §<section>: <principle>
**Requested fix (minimal):**
- Change `<file>:<line>` to `<what>`.
- Or update the test assertion to `<what>` (if the test is wrong, not the code).
**What already passes:**
- N/M tests pass.
- Lazy-import invariant preserved ✅ (or not — state explicitly).
@claude please push a fix. Follow AGENTS.md principles: minimal change, protocol-driven, no perf impact, lazy imports, backward-compatible, safe defaults. Make sure the PR is robust — run the tests locally before force-pushing.
EOF
)"
```
### Loop
After commenting:
```bash
echo "Waiting 10 minutes for Claude to push fixes..."
sleep 600
# → return to Phase 12 (fetch new commits, re-run checks)
```
**The assistant runs this `sleep 600` itself — it does NOT pause the loop to ask the user "check now".** After the 10-minute wait completes, the assistant immediately re-fetches the PR, re-runs the test suite, and either merges, posts the next feedback round, or reports a final status. The human is only prompted when:
- The PR merges successfully (report + move to next issue).
- The 3-round feedback cap is hit (escalate).
- A design decision is needed that the assistant cannot make unilaterally (e.g. "should `allow` policy persist or not?").
Repeat Phases 12 → 13 → 14 until the mergeability gate in Phase 13 is fully green, or escalate to a human after 3 failed rounds.
### When the PR has merge conflicts
If `mergeStateStatus=DIRTY`, ask Claude to rebase rather than resolving conflicts yourself on non-trivial logic:
```bash
gh pr comment $PR --repo $REPO --body "@claude this PR has merge conflicts with \`main\` (PR #<X> was merged, touching the same regions). Please rebase onto latest \`main\`, re-run \`pytest <paths>\`, and force-push."
```
---
## Phase 15 — Merge to `main`
Once Phase 13's gate is fully green:
### 15a. Final diff review against AGENTS.md
```bash
gh pr diff $PR --repo $REPO | less
```
**Hard gate — every box must be ticked before merge:**
- [ ] **Protocol-driven core (§4.1)**: no heavy implementations leaked into `praisonaiagents`.
- [ ] **No perf impact (§4.2)**: lazy imports confirmed; import benchmark within ±2 %.
- [ ] **DRY (§4.3)**: no new duplication; existing protocols/adapters reused where possible.
- [ ] **Agent-centric (§4.4)**: API centers on agents/sessions/tools/memory.
- [ ] **Async-safe + multi-agent safe (§4.5)**: no shared mutable globals; locks where needed.
- [ ] **Invariants preserved (§4.6)**: backward compatible, safe defaults, deterministic tests.
- [ ] **Naming conventions (§4.9)**: `XProtocol` for interfaces, `XAdapter` for impls, `add_*`/`get_*`/`save`/`load` verbs.
- [ ] No `.md` files added beyond those explicitly requested (per user global rule).
- [ ] Tests run locally with `timeout` — never hang (per user global rule).
### 15b. Merge
```bash
gh pr merge $PR --repo $REPO --squash --delete-branch
# --squash preserves linear main; --delete-branch keeps the repo clean
```
### 15c. Verify
```bash
gh pr view $PR --repo $REPO --json state,mergedAt,mergeCommit
gh issue view $ISSUE_NUM --repo $REPO --json state # should auto-close
```
---
# Orchestration Snippet (one-shot reference)
For a single end-to-end invocation, chain Part B phases:
```bash
#!/usr/bin/env bash
set -euo pipefail
REPO=MervinPraison/PraisonAI
ISSUE_NUM=<fill>
# Phase 10: wait for implementing agents
sleep 600
# Phase 11: ensure PR exists
BRANCH=$(gh api repos/$REPO/branches --paginate \
--jq ".[] | select(.name | startswith(\"claude/issue-$ISSUE_NUM\")) | .name" | head -1)
PR=$(gh pr list --repo $REPO --state open --head "$BRANCH" --json number --jq '.[0].number' 2>/dev/null || true)
if [ -z "$PR" ] && [ -n "$BRANCH" ]; then
TITLE=$(gh api repos/$REPO/commits/$BRANCH --jq '.commit.message' | head -1)
gh pr create --repo $REPO --head "$BRANCH" --base main \
--title "$TITLE" --body "Closes #$ISSUE_NUM"
PR=$(gh pr list --repo $REPO --state open --head "$BRANCH" --json number --jq '.[0].number')
fi
echo "Tracking PR #$PR"
# Phase 12: wait for reviewers + CI
sleep 600
# Phases 13–14: validate + feedback loop (cap at 3 rounds)
for round in 1 2 3; do
echo "=== Validation round $round ==="
# clone + pytest (per feature) — if green break; else gh pr comment + sleep 600
break # placeholder
done
# Phase 15: merge
gh pr merge $PR --repo $REPO --squash --delete-branch
gh issue view $ISSUE_NUM --repo $REPO --json state
```
---
## Checklist — Before Merging
- [ ] Issue exists and describes the work
- [ ] PR exists and references the issue (`Closes #N`)
- [ ] Branch was fetched and tests were run **locally** — not just CI-trusted
- [ ] All PR-relevant tests pass with zero failures
- [ ] CI matrix (3.10 / 3.11 / 3.12) is all green
- [ ] Lazy-import / cold-import invariants verified if optional deps added
- [ ] Diff reviewed against every AGENTS.md §4 principle
- [ ] `mergeStateStatus` in `CLEAN`/`UNSTABLE`, never `DIRTY`/`BLOCKED`
- [ ] No files outside the issue's scope were changed
- [ ] If feedback was given, `@claude` had a chance to respond and fixed everything
---
## Quick Reference — Common Mistakes
| Mistake | Fix |
|---------|-----|
| Merging without running tests locally | Always `git clone` the branch and run `pytest` |
| Resolving complex conflicts manually | Ask `@claude` to rebase instead |
| Trusting CI alone | CI jobs can be skipped / out-of-date; local validation is source of truth |
| Vague feedback to `@claude` | Every comment must cite file, line, test name, error, and AGENTS.md section |
| Waiting forever | Cap loops at 3 rounds, then escalate to a human |
| Running commands without `timeout` | Always `timeout 60 ...` per user global rule |
| Creating `.md` docs proactively | Don't — user rule forbids unrequested `.md` files |
| Skipping diff review | Every merge needs a full-diff AGENTS.md pass |
---
## Hard Rules
1. **Never merge without local test validation.**
2. **Never merge when `mergeStateStatus = DIRTY` or `BLOCKED`.**
3. **Every `@claude` comment must be actionable** — file, line, exact fix, AGENTS.md ref.
4. **Cap feedback loops at 3 rounds** — escalate after that, don't spin forever.
5. **Use `--squash --delete-branch`** to keep `main` linear and the repo clean.
6. **Always verify** the issue auto-closed after merge.
7. **All `run_command` calls use `timeout`** to avoid hangs (user global rule).
8. **No proactive `.md` creation** beyond this workflow file (user global rule).
9. **Never ask the user "check now"**: between rounds the assistant runs `sleep 600` itself and keeps driving. Only return control to the human on merge, 3-round cap, or an irresolvable design decision.
+771
View File
@@ -0,0 +1,771 @@
---
description: Gap Implementation Prompts — Sequential agent tasks for PraisonAIUI feature gaps
---
# Gap Implementation Prompts
Execute these prompts **sequentially**, one at a time. Each prompt is self-contained with context, analysis steps, and implementation instructions. Complete one fully (analysis → implementation → verification) before starting the next.
Reference: gap_analysis.md in the project's brain directory for full context.
---
---
## PROMPT 1: Channel Management Tab (G1 — Phase 1, Critical)
You are an expert AI engineer. Your task: **Add a Channel Management dashboard tab to PraisonAIUI** that surfaces the existing bot channel infrastructure from the PraisonAI package.
### Context
PraisonAI package already has a full channel/bot system:
- **Bots directory**: `~/praisonai-package/src/praisonai/praisonai/bots/` (26 files)
- Discord bot: `discord.py`, `_discord_approval.py`
- Slack bot: `slack.py`, `_slack_approval.py`
- Telegram bot: `telegram.py`, `_telegram_approval.py`
- WhatsApp bot: `whatsapp.py`, `_whatsapp_web_adapter.py`
- Base infra: `bot.py`, `_session.py`, `_rate_limit.py`, `_resilience.py`, `_approval.py`, `_approval_base.py`, `_http_approval.py`, `_webhook_approval.py`, `media.py`, `_commands.py`, `_debounce.py`, `_ack.py`, `_chunk.py`, `_protocol_mixin.py`, `_config_schema.py`, `_registry.py`
- **Gateway**: `~/praisonai-package/src/praisonai/praisonai/gateway/server.py` (1102 lines, 41KB)
- `WebSocketGateway.health()` — returns per-channel bot health status
- `WebSocketGateway.start_channels(channels_cfg)` — starts bot instances from config
- `WebSocketGateway._create_bot(channel_type, token, agent, config, ch_cfg)` — creates bot per channel
- `WebSocketGateway._run_bot_safe(name, bot)` — runs with error isolation
- `WebSocketGateway._inject_routing_handler(channel_name, bot)` — routing-aware handlers
PraisonAIUI server: `~/PraisonAIUI/src/praisonaiui/server.py` — Starlette app with SSE streaming, existing dashboard tabs via `/api/*` endpoints and `@page()` decorator.
PraisonAIUI frontend dashboard: `~/PraisonAIUI/src/praisonaiui/templates/frontend/plugins/` — JavaScript plugins for dashboard tabs (e.g., `topnav.js` for tab rendering).
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Inventory the bot system**: Read every file in `~/praisonai-package/src/praisonai/praisonai/bots/`. Understand:
- How each bot is initialized (constructor params, tokens, agent binding)
- What status/health information each bot exposes
- How `_resilience.py` tracks bot health
- How `_config_schema.py` defines channel configuration
- How `_registry.py` registers available channels
2. **Inventory the gateway**: Read `~/praisonai-package/src/praisonai/praisonai/gateway/server.py`. Understand:
- `WebSocketGateway.health()` — what data it returns about channels
- `start_channels()` — how channels are started from YAML config
- `_create_bot()` — bot factory pattern
- Channel routing: `_determine_routing_context()`, `_resolve_agent_for_message()`
3. **Inventory PraisonAIUI dashboard**: Read `~/PraisonAIUI/src/praisonaiui/server.py`. Understand:
- How existing `/api/*` endpoints work (pattern for adding new ones)
- How `@page()` decorator registers dashboard pages
- How `_registered_pages` dict works
- How dashboard tabs are rendered in the frontend
4. **Inventory the frontend**: Read `~/PraisonAIUI/src/praisonaiui/templates/frontend/plugins/topnav.js` and other dashboard plugins. Understand:
- How tabs are dynamically rendered
- How tab data is fetched from `/api/*` endpoints
- The pattern for adding a new dashboard tab
5. **Gap Analysis**: Document exactly what's missing:
- Backend: API endpoint to query channel status
- Frontend: Dashboard tab component for channels
- Integration: How PraisonAIUI will communicate with the gateway for channel health
6. **Plan**: Produce a step-by-step implementation plan listing exact files to create/modify.
### PHASE 2 — Implementation (MUST)
1. **Backend — Add `/api/channels` endpoint** in `~/PraisonAIUI/src/praisonaiui/server.py`:
- `GET /api/channels` — Returns list of configured channels with status (name, type, health, connected, last_active)
- `POST /api/channels/{name}/restart` — Restart a specific channel bot
- The endpoint should integrate with the gateway's `health()` method or maintain its own channel registry
- Follow the exact pattern of existing `/api/overview`, `/api/config` endpoints
2. **Frontend — Add Channels dashboard page**:
- Create a new dashboard plugin or add to existing dashboard rendering
- Show a card/table for each channel: icon, name, status (online/offline/error), message count, last activity
- Add status indicators (green/yellow/red dots)
- Add restart button per channel
- Follow the existing dashboard tab rendering pattern from `topnav.js`
3. **Register the tab**: Ensure the Channels tab appears in the dashboard navigation alongside existing tabs (Agents, Config, Logs)
### PHASE 3 — Verification (MUST)
1. Run the PraisonAIUI dev server and verify the Channels tab appears
2. Verify `/api/channels` returns correct data
3. Verify the UI renders channel cards with accurate status
4. Test with at least one bot configured and verify status updates
5. Verify no regressions in existing dashboard tabs
6. Document what was implemented and what remains
---
---
## PROMPT 2: Scheduler/Cron Tab (G2 — Phase 1, Critical)
You are an expert AI engineer. Your task: **Add a Scheduler dashboard tab to PraisonAIUI** that surfaces the existing AgentScheduler from the PraisonAI package.
### Context
PraisonAI package has a complete scheduler system:
- **Scheduler directory**: `~/praisonai-package/src/praisonai/praisonai/scheduler/` (7 files)
- `agent_scheduler.py` (21KB) — `AgentScheduler` class:
- `__init__(agent, task, config, on_success, on_failure, timeout, max_cost)`
- `start(schedule_expr, max_retries, run_immediately)` — schedule expressions: `"hourly"`, `"daily"`, `"*/6h"`, `"3600"` (seconds)
- `stop()` — graceful shutdown
- `get_stats()` — execution stats including cost
- `execute_once()` — one-time run
- `from_yaml(yaml_path, ...)` — create from agents.yaml
- `from_recipe(recipe_name, ...)` — create from recipe
- `start_from_yaml_config()` — start using YAML schedule config
- `daemon_manager.py` (7KB) — background process lifecycle
- `state_manager.py` (4KB) — persistent execution state
- `base.py` (4KB) — `ScheduleParser`, `PraisonAgentExecutor` base classes
- `yaml_loader.py` (6KB) — YAML schedule config loading
- **Top-level**: `~/praisonai-package/src/praisonai/praisonai/agent_scheduler.py` (11KB) — convenience wrapper
PraisonAIUI: `~/PraisonAIUI/src/praisonaiui/server.py` — Starlette app. Existing pattern: API endpoints return JSON, dashboard renders tabs.
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read the full scheduler system**: Go through every file in `~/praisonai-package/src/praisonai/praisonai/scheduler/`:
- `agent_scheduler.py` — understand the full `AgentScheduler` lifecycle (init → start → _run_schedule → _execute_with_retry → stop)
- `base.py` — understand `ScheduleParser.parse()` for schedule expression formats
- `daemon_manager.py` — understand how daemon processes are managed (start/stop/status)
- `state_manager.py` — understand how execution state is persisted (where, format)
- `yaml_loader.py` — understand YAML config format for schedules
2. **Understand the data model**: What data does a scheduled agent have?
- Schedule expression, agent identity, task description, max retries, timeout, max cost
- Execution stats: total_runs, successful_runs, failed_runs, total_cost, last_run, next_run
3. **Inventory PraisonAIUI**: Read `server.py` to understand the pattern for adding CRUD API endpoints.
4. **Gap Analysis**: Document exactly what's needed:
- API: CRUD endpoints for schedules (list, create, update, delete, run-now, get-stats)
- Storage: Where to persist schedule definitions (YAML file? database? in-memory?)
- Frontend: Scheduler tab with schedule list, create/edit form, run history
5. **Plan**: Step-by-step with exact files to create/modify.
### PHASE 2 — Implementation (MUST)
1. **Backend — Add Scheduler API endpoints** in `~/PraisonAIUI/src/praisonaiui/server.py`:
- `GET /api/schedules` — List all scheduled agents with status and stats
- `POST /api/schedules` — Create a new schedule (agent, task, schedule_expr, max_retries, timeout, max_cost)
- `PUT /api/schedules/{id}` — Update schedule configuration
- `DELETE /api/schedules/{id}` — Remove a schedule
- `POST /api/schedules/{id}/run` — Trigger immediate execution
- `POST /api/schedules/{id}/stop` — Stop a running schedule
- `GET /api/schedules/{id}/stats` — Get execution statistics
- Integrate with `AgentScheduler` class from praisonai-package, importing it appropriately
2. **Backend — Schedule persistence**:
- Store schedule definitions in a YAML/JSON file alongside the existing config
- Load schedules on server startup and start them automatically
- Track run history in-memory with periodic flush
3. **Frontend — Add Scheduler dashboard page**:
- Schedule list: table/cards showing each schedule (name, expression, status, last run, next run, cost)
- Create/Edit form: agent selector, task input, schedule expression picker (presets: hourly/daily/weekly + custom cron), retry/timeout/cost settings
- Run history: expandable section per schedule showing past executions with results
- Action buttons: Start, Stop, Run Now, Edit, Delete
- Status indicators: Running (green pulse), Stopped (gray), Failed (red)
4. **Register the tab**: Add Scheduler tab to dashboard navigation.
### PHASE 3 — Verification (MUST)
1. Create a test schedule with a simple agent task and verify it appears in the UI
2. Test start/stop/run-now actions
3. Verify execution stats update after runs
4. Verify schedules persist across server restarts
5. Verify no regressions in existing functionality
6. Document what was implemented
---
---
## PROMPT 3: Jobs Management Tab (G3 — Phase 1, Critical)
You are an expert AI engineer. Your task: **Add a Jobs Management dashboard tab to PraisonAIUI** that surfaces the existing async Jobs API from the PraisonAI package.
### Context
PraisonAI package has a complete async jobs system:
- **Jobs directory**: `~/praisonai-package/src/praisonai/praisonai/jobs/` (6 files)
- `executor.py` (14KB) — `JobExecutor` class:
- `__init__(store, max_concurrent, default_timeout, cleanup_interval)`
- `submit(job)` — submit job for execution
- `cancel(job_id)` — cancel running job
- `start()` / `stop()` — executor lifecycle
- `register_progress_callback(job_id, callback)` — real-time progress
- `_run_agent(job)` / `_run_recipe(job)` / `_run_praisonai_agents(job)` — multiple execution modes
- `_send_webhook(job)` — webhook notifications on completion
- `get_stats()` — executor statistics
- `router.py` (11KB) — FastAPI router (`create_router(store, executor)`):
- `POST /jobs` → `submit_job` (returns 202 + Location header + Retry-After)
- `GET /jobs` → `list_jobs` (filter by status, session_id, pagination)
- `GET /jobs/{id}/status` → `get_job_status`
- `GET /jobs/{id}/result` → `get_job_result` (409 if not complete)
- `DELETE /jobs/{id}/cancel` → `cancel_job` (409 if already complete)
- `DELETE /jobs/{id}` → `delete_job` (only completed)
- `GET /jobs/{id}/stream` → `stream_job` (SSE: status/progress/result/error events)
- Supports idempotency via `Idempotency-Key` header
- `models.py` (10KB) — `Job`, `JobStatus`, `JobSubmitRequest`, `JobSubmitResponse`, `JobStatusResponse`, `JobResultResponse`, `JobListResponse`
- `store.py` (7KB) — `JobStore` — in-memory + persistent storage
- `server.py` (5KB) — standalone server mounting the router
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read the full jobs system**: Go through every file in `~/praisonai-package/src/praisonai/praisonai/jobs/`:
- `models.py` — understand all DTOs and status enum
- `store.py` — understand storage backend (how jobs are persisted, queried)
- `executor.py` — understand execution lifecycle (submit → execute → complete/fail)
- `router.py` — understand all HTTP endpoints and their contracts
- `server.py` — understand how the standalone server mounts the router
2. **Determine integration approach**: The jobs router is a FastAPI router. PraisonAIUI uses Starlette. Determine:
- Can the jobs router be mounted directly in PraisonAIUI's Starlette app?
- Or do we need to adapt the endpoints?
- How to share the `JobStore` and `JobExecutor` instances with the main app
3. **Gap Analysis**: Document what's needed:
- Backend: Mount or adapt the jobs router into PraisonAIUI
- Frontend: Jobs dashboard showing job list, status, progress, results with real-time SSE updates
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Mount Jobs API** in PraisonAIUI:
- Initialize `JobStore` and `JobExecutor` in `create_app()`
- Mount the jobs router at `/api/jobs/*` or adapt endpoints to Starlette
- Ensure the executor starts when the app starts and stops when it stops
2. **Frontend — Add Jobs dashboard page**:
- Jobs list: table with columns (ID, agent, status, progress %, submitted, duration, cost)
- Status badges: Pending (gray), Running (blue pulse), Completed (green), Failed (red), Cancelled (yellow)
- Real-time progress: Use SSE from `/jobs/{id}/stream` to update progress bars
- Job detail view: expandable row showing full result, error message, webhook status
- Actions: Submit new job (form), Cancel running job, Delete completed job
- Filters: by status, date range, agent
3. **Register the tab**: Add Jobs tab to dashboard navigation.
### PHASE 3 — Verification (MUST)
1. Submit a test job via the UI and verify it appears in the list
2. Verify real-time progress updates via SSE
3. Test cancel and delete actions
4. Verify job results are displayed correctly after completion
5. Verify no regressions
6. Document what was implemented
---
---
## PROMPT 4: Usage Analytics Upgrade (G6 — Phase 1, Critical)
You are an expert AI engineer. Your task: **Upgrade PraisonAIUI's usage analytics** from basic token counters to per-model cost tracking with time-series charts.
### Context
Current state in PraisonAIUI (`~/PraisonAIUI/src/praisonaiui/server.py`):
- `_usage_stats` — simple in-memory dict tracking basic token counts
- `GET /api/usage` — returns this dict as JSON
- No cost calculation, no per-model breakdown, no time-series data, no charts
OpenClaw comparison: ~80KB of usage view code with per-model costs, per-session breakdown, time-series charts, export functionality.
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read PraisonAIUI usage tracking**: Read `server.py` and search for `_usage_stats`, understand:
- Where/when usage is tracked (during `run_agent`, on SSE events)
- What data is currently captured (input_tokens, output_tokens, total_tokens)
- How the data flows from agent execution to the stats dict
2. **Research model pricing**: Understand common LLM pricing models:
- OpenAI: per-1K tokens, different rates for input vs output, varies by model
- Anthropic: per-1K tokens, input vs output
- Google: per-1K tokens
- Design a cost table data structure
3. **Design time-series storage**: Plan how to store usage data over time:
- In-memory ring buffer with periodic flush to disk? SQLite? JSON file?
- Granularity: per-request? per-minute? per-hour?
- Retention: how much history to keep?
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Enhanced usage tracking**:
- Create a `UsageTracker` class (or enhance the existing tracking in `server.py`):
- Track per-request: model, input_tokens, output_tokens, cost, timestamp, session_id, agent_name
- Maintain aggregations: by model, by session, by agent, by time period
- Cost calculation: configurable cost table (price per 1K input/output tokens per model)
- Update `/api/usage` to return rich data:
- `GET /api/usage` — summary (total cost, total tokens, by model, by period)
- `GET /api/usage/details` — detailed time-series data for charts
- `GET /api/usage/models` — per-model breakdown
- `GET /api/usage/sessions` — per-session breakdown
2. **Backend — Cost table**:
- Default cost table with common LLM model pricing
- Configurable via YAML config (`cost_per_model` section)
- Auto-detect model from provider responses
3. **Frontend — Usage analytics dashboard**:
- Summary cards: Total cost ($), Total tokens, Requests count, Avg cost per request
- Chart: Token/cost usage over time (line chart, selectable time range: 1h/24h/7d/30d)
- Model breakdown: Bar chart or table showing cost per model
- Session breakdown: Table showing per-session usage
- Use a lightweight charting library (e.g., Chart.js via CDN, or SVG-based inline charts)
4. **Persistence**: Save usage data to a JSON/SQLite file so it survives server restarts.
### PHASE 3 — Verification (MUST)
1. Run an agent chat and verify usage data is captured with model and cost
2. Verify `/api/usage` returns enriched data
3. Verify charts render correctly in the dashboard
4. Verify data persists across server restarts
5. Verify no performance impact on chat response times
6. Document what was implemented
---
---
## PROMPT 5: Skills/Tools Management Tab (G4 — Phase 2, High)
You are an expert AI engineer. Your task: **Add a Skills/Tools Management dashboard tab to PraisonAIUI** that surfaces available tools and allows enable/disable/configuration.
### Context
PraisonAI package has tool infrastructure:
- **Capabilities**: `~/praisonai-package/src/praisonai/praisonai/capabilities/` (27 files)
- `skills.py` (3KB) — skills endpoint
- `completions.py`, `responses.py`, `assistants.py`, `files.py`, `images.py`, `audio.py`, `embeddings.py`, `fine_tuning.py`, `batches.py`, `guardrails.py`, `moderations.py`, `ocr.py`, `rag.py`, `realtime.py`, `rerank.py`, `search.py`, `videos.py`, `mcp.py`, `a2a.py`, `messages.py`, `vector_stores.py`, `container_files.py`, `containers.py`, `passthrough.py`
- **Tool resolver**: `~/praisonai-package/src/praisonai/praisonai/tool_resolver.py` (14KB) — dynamic tool resolution by name
- **Tools directory**: `~/praisonai-package/src/praisonai/praisonai/tools/` — audio.py, glob_tool.py, grep_tool.py, multiedit.py
- **Inbuilt tools**: `~/praisonai-package/src/praisonai/praisonai/inbuilt_tools/` — autogen_tools.py
- **Skills examples**: `~/praisonai-package/examples/skills/` — basic_skill_usage.py, create_skill_example.py, custom_skill_example.py
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read the tool/skills system**:
- `capabilities/skills.py` — understand the skills endpoint interface
- `tool_resolver.py` — understand how tools are discovered, resolved, loaded
- `tools/` directory — understand the built-in tool pattern
- `capabilities/__init__.py` — understand how capabilities are registered and discovered
- Skills examples — understand the user-facing skill creation pattern
2. **Understand capability registration**: How does PraisonAI know which capabilities are available?
- Are they auto-discovered? Explicitly registered? Config-driven?
- Can individual capabilities be enabled/disabled?
3. **Gap Analysis**: Document what's needed:
- API: Endpoint to list tools, get tool details, enable/disable, set API keys
- Frontend: Skills tab with tool catalog, status toggles, API key configuration
- Integration: How to wire capability enable/disable to the provider system
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Skills API** in PraisonAIUI:
- `GET /api/skills` — List all available tools/skills with status (name, type, enabled, description, required_keys)
- `PUT /api/skills/{name}` — Enable/disable a skill
- `PUT /api/skills/{name}/config` — Set API keys or configuration for a skill
- `GET /api/skills/{name}` — Get detailed info about a specific skill
2. **Frontend — Skills dashboard page**:
- Tool catalog: Grid/list of available tools with icons, names, descriptions
- Status toggles: Enable/disable switch per tool
- Configuration: Expandable config section per tool for API keys and settings
- Categories: Group by type (built-in, capabilities, custom)
- Search/filter: Find tools by name or category
3. **Register the tab**: Add Skills tab to dashboard navigation.
### PHASE 3 — Verification (MUST)
1. Verify the skills list loads with correct tool inventory
2. Test enable/disable toggle and verify it affects agent tool availability
3. Test API key configuration
4. Verify no regressions
5. Document what was implemented
---
---
## PROMPT 6: Agent CRUD from Dashboard (G7 — Phase 2, High)
You are an expert AI engineer. Your task: **Add full Agent CRUD (Create, Update, Delete) to the PraisonAIUI dashboard**, extending beyond the current read-only agent listing.
### Context
Current state:
- PraisonAIUI `server.py`: `GET /agents` returns a list of registered agents (read-only)
- PraisonAI gateway: `WebSocketGateway.register_agent(agent, agent_id)` and `unregister_agent(agent_id)` exist
- Agents are currently registered programmatically via Python code, not from the UI
OpenClaw comparison: Full agent CRUD with file editing (system prompt, instructions), tool profile overrides (allow/deny lists), identity management (name, avatar).
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read the agent system end-to-end**:
- `~/PraisonAIUI/src/praisonaiui/server.py` — how agents are registered, listed, used during `run_agent`
- `~/praisonai-package/src/praisonai/praisonai/gateway/server.py` — `register_agent()`, `unregister_agent()`, `get_agent()`, `list_agents()`, `_create_agents_from_config()`
- Understand the Agent class from praisonaiagents: what properties can be configured?
2. **Understand agent configuration format**:
- How are agents defined in YAML? What fields?
- System prompt, instructions, tool lists, model selection, temperature, etc.
- How are agents loaded from config at startup?
3. **Design the CRUD model**: What data does agent create/update need?
- Name, description, system prompt, instructions, model, temperature
- Tool allow/deny lists
- Avatar/icon
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Agent CRUD endpoints** in PraisonAIUI:
- `GET /agents` — (existing) List agents with full details
- `POST /agents` — Create a new agent (name, description, system_prompt, instructions, model, tools, config)
- `PUT /agents/{id}` — Update agent configuration
- `DELETE /agents/{id}` — Remove an agent
- `GET /agents/{id}` — Get detailed agent info including system prompt and tools
- Persist agent definitions to a YAML/JSON file
2. **Frontend — Agent editor**:
- Agent list with Create New button
- Agent editor form: name, description, model selector, temperature slider
- System prompt editor: multi-line text area with syntax highlighting
- Instructions editor: multi-line text area
- Tool configuration: checkbox list of available tools
- Save/Cancel/Delete buttons
- Inline validation
3. **Integration**: New/updated agents should be live-registerable without server restart.
### PHASE 3 — Verification (MUST)
1. Create a new agent from the dashboard and verify it appears in the list
2. Edit an agent's system prompt and verify the change takes effect in chat
3. Delete an agent and verify it's removed
4. Verify agents persist across server restarts
5. Document what was implemented
---
---
## PROMPT 7: Exec Approval Dashboard (G5 — Phase 2, High)
You are an expert AI engineer. Your task: **Add an Execution Approval dashboard to PraisonAIUI** that surfaces the existing approval system from the PraisonAI package bots.
### Context
PraisonAI package has a comprehensive approval system:
- **Approval infrastructure** in `~/praisonai-package/src/praisonai/praisonai/bots/`:
- `_approval.py` — Core approval logic
- `_approval_base.py` — Base class for approval backends
- `_discord_approval.py` — Discord-specific approval flow
- `_slack_approval.py` — Slack-specific approval flow
- `_telegram_approval.py` — Telegram-specific approval flow
- `_http_approval.py` — HTTP webhook-based approvals
- `_webhook_approval.py` — Webhook notification for approvals
The approval system allows agents to request human approval before executing certain actions (tool calls, external API calls, destructive operations).
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read the full approval system**:
- `_approval_base.py` — understand the base protocol/interface for approvals
- `_approval.py` — understand the core approval lifecycle (request → pending → approve/deny)
- `_http_approval.py` — understand the HTTP-based approval mechanism (this is most relevant for UI integration)
- Each channel-specific approval file — understand how they present approval requests
2. **Understand the approval data model**:
- What information is in an approval request? (agent, tool, arguments, risk level, timestamp)
- What are the possible actions? (approve, deny, approve-always, deny-always)
- How are policies stored? (auto-approve lists, always-deny lists)
3. **Determine integration approach**:
- Can `_http_approval.py` be extended to serve as the UI backend?
- Or do we need a separate approval queue accessible from PraisonAIUI?
- Real-time: WebSocket for instant approval notifications?
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Approval API** in PraisonAIUI:
- `GET /api/approvals` — List pending approval requests
- `POST /api/approvals/{id}/approve` — Approve a request
- `POST /api/approvals/{id}/deny` — Deny a request
- `GET /api/approvals/policies` — List approval policies (auto-approve, always-deny)
- `PUT /api/approvals/policies` — Update policies
- `GET /api/approvals/history` — Past approval decisions
- WebSocket or SSE endpoint for real-time approval notifications
2. **Frontend — Approval dashboard page**:
- Pending queue: Cards showing each pending request with agent name, action, arguments, risk level, timestamp
- Approve/Deny buttons with optional "always" checkbox
- Policy editor: Configure auto-approve/deny rules per tool, per agent
- History: Table of past approvals with decision, timestamp, details
- Real-time: New approvals appear instantly via WebSocket/SSE
- Notification badge on the tab showing pending count
3. **Register the tab**: Add Approvals tab to dashboard navigation with badge.
### PHASE 3 — Verification (MUST)
1. Configure an agent with an approval-required tool
2. Trigger the tool and verify an approval request appears in the dashboard
3. Approve it and verify the agent continues execution
4. Deny a request and verify the agent handles it gracefully
5. Test auto-approve policy and verify it works
6. Document what was implemented
---
---
## PROMPT 8: OpenAI-Compatible API Routes (G — Phase 2, High)
You are an expert AI engineer. Your task: **Mount PraisonAI's 27 OpenAI-compatible capability endpoints in PraisonAIUI** so they are accessible via `/v1/*` routes.
### Context
PraisonAI package has 27 OpenAI-compatible capability endpoints:
- **Directory**: `~/praisonai-package/src/praisonai/praisonai/capabilities/` (27 files)
- Key endpoints: `completions.py`, `responses.py`, `assistants.py`, `files.py`, `images.py`, `audio.py`, `embeddings.py`, `fine_tuning.py`, `batches.py`, `guardrails.py`, `moderations.py`, `ocr.py`, `rag.py`, `realtime.py`, `rerank.py`, `search.py`, `skills.py`, `videos.py`, `mcp.py`, `a2a.py`, `messages.py`, `vector_stores.py`, `container_files.py`, `containers.py`, `passthrough.py`
- `__init__.py` (9KB) — likely contains registration/routing logic
PraisonAIUI uses Starlette. The capabilities likely use FastAPI routers.
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read `capabilities/__init__.py`**: Understand how capabilities are registered, what router/app they expose
2. **Read `completions.py`**: Understand the endpoint pattern (request/response format, OpenAI compatibility)
3. **Read `responses.py`**: Understand the responses API endpoint
4. **Understand the mount pattern**: How to integrate FastAPI routers into Starlette apps
5. **Plan**: Determine which capabilities to mount, routing prefix (`/v1/`), authentication, and configuration
### PHASE 2 — Implementation (MUST)
1. **Mount capabilities in PraisonAIUI**:
- Import the capabilities router/app from praisonai-package
- Mount at `/v1/` prefix in PraisonAIUI's Starlette app (in `create_app()`)
- Ensure proper CORS, authentication, and error handling
- Key routes: `/v1/chat/completions`, `/v1/responses`, `/v1/embeddings`, `/v1/images/generations`, etc.
2. **Configuration**: Add capability enable/disable flags in PraisonAIUI config YAML
3. **Documentation**: Add API docs endpoint or link to capability documentation
### PHASE 3 — Verification (MUST)
1. Test `/v1/chat/completions` with a standard OpenAI SDK client
2. Test `/v1/responses` endpoint
3. Verify compatibility with OpenAI Python SDK
4. Verify no regressions in existing PraisonAIUI functionality
5. Document the available endpoints
---
---
## PROMPT 9: Real-Time Log Streaming (G9 — Phase 3, Polish)
You are an expert AI engineer. Your task: **Upgrade PraisonAIUI's log viewer from polling to real-time WebSocket streaming**.
### Context
Current state in PraisonAIUI (`~/PraisonAIUI/src/praisonaiui/server.py`):
- `_log_buffer` — in-memory deque (500 entries max)
- `GET /api/logs` — returns the entire buffer as JSON (polling-based)
- Frontend polls this endpoint periodically
Goal: Real-time log tailing via WebSocket, with level filtering and search.
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read current logging implementation**: Search `server.py` for `_log_buffer`, understand how logs are captured and stored
2. **Understand Python logging integration**: How are Python logger messages routed to `_log_buffer`?
3. **Design WebSocket approach**: Plan the WebSocket endpoint, message format, filtering protocol
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — WebSocket log endpoint**:
- `WS /api/logs/stream` — WebSocket endpoint that streams log entries in real-time
- Support filter parameters: `level` (DEBUG/INFO/WARNING/ERROR), `search` (text match)
- Keep the existing `GET /api/logs` for backward compatibility
- Use Python logging handler that broadcasts to connected WebSocket clients
2. **Frontend — Enhanced log viewer**:
- Real-time log display with auto-scroll
- Level filter buttons (DEBUG, INFO, WARNING, ERROR) with color coding
- Search box for text filtering
- Pause/resume button to stop auto-scroll
- Clear button
- Timestamp formatting
- Log level color coding (gray=DEBUG, blue=INFO, yellow=WARNING, red=ERROR)
### PHASE 3 — Verification (MUST)
1. Connect to the WebSocket and verify real-time log streaming
2. Test level filtering
3. Test search filtering
4. Verify auto-scroll and pause/resume
5. Verify backward compatibility of `GET /api/logs`
6. Document what was implemented
---
---
## PROMPT 10: Config Form Editor (G8 — Phase 3, Polish)
You are an expert AI engineer. Your task: **Upgrade PraisonAIUI's config editor from raw YAML to a schema-driven form editor**.
### Context
Current state:
- PraisonAIUI `server.py`: `GET /api/config` returns raw YAML, `POST /api/config` writes raw YAML
- PraisonAI package: `bots/_config_schema.py` — configuration schema definition
- No form rendering, no validation, no guided editing
OpenClaw comparison: Full schema-validated form rendering with live apply.
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read current config handling**: `server.py` → `api_config_handler`, `load_config_from_yaml`
2. **Read `_config_schema.py`**: Understand the config schema format (JSON Schema? Custom?)
3. **Understand the config structure**: What sections exist? (provider, model, channels, agents, scheduler, etc.)
4. **Design form rendering**: Plan how to render schema-driven forms in the frontend
5. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Config schema endpoint**:
- `GET /api/config/schema` — Return the config schema (JSON Schema format)
- `POST /api/config/validate` — Validate config changes before applying
- `POST /api/config/apply` — Apply config changes with validation and live reload
2. **Frontend — Form editor**:
- Tab within the Config page: "Form View" vs "YAML View" toggle
- Auto-generated form from JSON Schema:
- Text inputs for strings, number inputs for numbers
- Toggle switches for booleans
- Dropdowns for enums (model selection, provider selection)
- Nested sections with collapsible panels
- Validation: Real-time validation with error messages
- Save button with confirmation
- Reset to defaults button
- Keep raw YAML editor as alternative view
### PHASE 3 — Verification (MUST)
1. Verify the form renders all config sections correctly
2. Test editing a config value via form and verify it's saved
3. Test validation with invalid values
4. Verify toggle between form and YAML views
5. Verify config changes take effect without restart (where possible)
6. Document what was implemented
---
---
## PROMPT 11: Session Advanced Operations (G10 — Phase 3, Polish)
You are an expert AI engineer. Your task: **Add advanced session operations to PraisonAIUI**: reset context, compact memory, and session preview.
### Context
Current state in PraisonAIUI (`server.py`):
- `GET /sessions` — List sessions
- `GET /sessions/{id}` — Get session detail
- `GET /sessions/{id}/runs` — Get message history
- `DELETE /sessions/{id}` — Delete session
- `PATCH /sessions/{id}` — Rename/tag session
- `POST /sessions` — Create session
Missing (present in OpenClaw): Reset context (clear memory but keep session), Compact memory (summarize old messages to reduce context), Preview (rich preview of session content).
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read current session system** in `server.py`: Understand how sessions store messages, how context is managed
2. **Read session system in praisonai-package**: `bots/_session.py` — understand session state management
3. **Design**: Plan reset (clear messages, keep metadata), compact (LLM-summarize old messages), preview (formatted message display)
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Advanced session endpoints**:
- `POST /sessions/{id}/reset` — Clear all messages but keep session metadata
- `POST /sessions/{id}/compact` — Summarize old messages using the LLM, replace them with a summary message
- `GET /sessions/{id}/preview` — Return formatted preview (first/last messages, total count, token estimate)
2. **Frontend — Enhanced session management**:
- Add action buttons to session list: Reset, Compact, Preview
- Reset confirmation dialog
- Compact: Show before/after message count and token savings
- Preview: Modal showing session summary without loading full history
### PHASE 3 — Verification (MUST)
1. Test reset: verify messages are cleared, session metadata preserved
2. Test compact: verify old messages are replaced with a summary
3. Test preview: verify formatted preview is returned
4. Verify no regressions in existing session operations
5. Document what was implemented
---
---
## PROMPT 12: Auth Enhancements (G11 — Phase 3, Polish)
You are an expert AI engineer. Your task: **Enhance PraisonAIUI's authentication** from a single `require_auth` flag to multi-mode auth support.
### Context
Current state in PraisonAIUI (`server.py`):
- `require_auth: bool` parameter in `create_app()` — single flag
- No token management, no API key support, no user-level access control
OpenClaw comparison: Token + password + trusted-proxy + device auth modes.
PraisonAI package security: `~/praisonai-package/src/praisonai/praisonai/security/` — security module (read this first).
### PHASE 1 — Analysis (MUST complete before implementing)
1. **Read current auth**: `server.py` → understand how `require_auth` is implemented
2. **Read praisonai-package security**: `~/praisonai-package/src/praisonai/praisonai/security/` — understand what security infrastructure exists
3. **Design multi-mode auth**:
- API key auth (for programmatic access)
- Token/session auth (for dashboard users)
- Optional password auth (for initial setup)
4. **Plan**: Step-by-step with exact files.
### PHASE 2 — Implementation (MUST)
1. **Backend — Auth middleware**:
- API key authentication: `X-API-Key` header or `?api_key=` query param
- Session token authentication: JWT or session cookie for dashboard
- Configurable auth mode in YAML config
- Auth middleware in Starlette that checks configured mode
2. **Frontend — Auth UI**:
- Login page (if password auth enabled)
- API key display/rotation in settings
- Session management (logout, token refresh)
3. **Configuration**: Auth section in YAML config with mode selection and credentials
### PHASE 3 — Verification (MUST)
1. Test API key auth with curl
2. Test session auth via dashboard login
3. Verify unauthenticated requests are rejected
4. Verify auth can be disabled for development
5. Document auth configuration options
+81
View File
@@ -0,0 +1,81 @@
---
description: PraisonAIUI product categories and differentiation
---
# UI Product Categories
PraisonAIUI supports three distinct styles, each serving a different use case:
## 1. Chat (`style: chat`)
- Full-screen conversational interface (like ChatGPT)
- Sidebar with session/conversation history
- Streaming responses, thinking indicators, tool calls
- Best for: single-agent chat, customer support, Q&A bots
## 2. Playground (`style: playground`)
- Input/output panel layout
- Agent selection, model switching, endpoint configuration
- Session management with agent profiles
- Best for: multi-agent experimentation, developer testing, agent debugging
## 3. UI Components (Widget mode)
- Embeddable components (copilot widget, sidebar panel, floating button)
- Integrates into existing apps/docs sites
- Configurable position: bottom-right, bottom-left, top-right, top-left
- Best for: adding AI to existing products, documentation copilots
## Key Differentiators
- **Chat** = conversation-first, full-page, session history
- **Playground** = multi-agent, experimentation, side-by-side panels
- **Components** = embeddable widgets for existing apps
When using AI, we mainly and primarily use PraisonAI as the backend ~/praisonai-package
When using Platform, we mainly and primarily use PraisonAI (Gateway) as the backend ~/praisonai-package
We will also support other providers, but PraisonAI will be the primary.
PraisonAI already has memory, knowledge, session management, and more. So where possible we will use PraisonAI's features.
## PraisonAI Backend Capabilities (~/praisonai-package)
The backend (`praisonaiagents`) already provides these features. The UI's job is to surface them:
- **Gateway**: EventType enum (20 types), GatewayEvent, GatewayMessage, GatewaySessionProtocol, GatewayClientProtocol
- **Streaming**: StreamEventType (REQUEST_START, FIRST_TOKEN, DELTA_TEXT, DELTA_TOOL_CALL, TOOL_CALL_END, STREAM_END, ERROR), StreamEvent, StreamMetrics, StreamEventEmitter
- **Memory**: Short-term, long-term, user-specific, auto-memory, file memory, rules, workflows (76KB+ implementation)
- **Knowledge**: RAG, vector store, chunking, query engine, rerankers, readers (41KB+ knowledge.py)
- **Sessions**: Full Session API with state persistence, agent chat history, memory/knowledge integration
- **Hooks**: Registry, middleware, runner, events, types (65KB+ system)
- **Approval**: Full human-in-the-loop approval with backends, registry, protocols
- **Bots/Channels**: Telegram (via gateway.yaml channel routing), extensible to Slack/Discord/WhatsApp etc. (Via Gateway)
- **Other**: MCP, guardrails, planning, sandbox, plugins, tools, thinking, escalation, checkpoints
## Goal of PraisonAIUI
One of the primary goals is: **make the web UI enable and surface these existing PraisonAI backend features**.
Except for the web UI itself, PraisonAI supports everything. This project fills that gap.
## Provider Protocol Architecture (Extensibility)
PraisonAIUI is **provider-agnostic**. The architecture uses a protocol-driven design so any AI backend can be swapped in:
- **`BaseProvider`** (`src/praisonaiui/provider.py`): Abstract base class any backend implements. Only `run()` is required — yields `RunEvent` objects.
- **`RunEvent`**: Structured dataclass with `type` (27 `RunEventType` values), optional fields for content, tool calls, reasoning, errors, agent info, and arbitrary `extra_data`.
- **`PraisonAIProvider`** (`src/praisonaiui/providers/__init__.py`): Default implementation wrapping the `@aiui.reply` callback system. Maps legacy queue events to `RunEvent`.
### Swapping Providers
```python
import praisonaiui
# Use any custom provider:
praisonaiui.set_provider(MyLangChainProvider())
# or
praisonaiui.set_provider(MyCrewAIProvider())
```
### Design Principles
- **Protocol-first**: All communication between UI and backend goes through `RunEvent` protocol — no tight coupling
- **PraisonAI primary, others welcome**: PraisonAI is the default, but the architecture doesn't lock you in
- **Frontend already ready**: The frontend `useSSE.ts` hook and components (`ToolCallDisplay`, `ThinkingSteps`, `MultimediaElements`) already handle all 27 `RunEventType` values — swapping the backend requires no frontend changes
Aim is by default it need to be protocol driven, so we can easily extend, or replace any providers or function accordingly. At the same time it also need to be capable of handling clients, and the clients will be of config driven, same like chainlit or yaml config and it should work.
+839
View File
@@ -0,0 +1,839 @@
---
description: Update install.sh and deploy PraisonAI to Kubernetes via Helm (CI/CD Pipeline)
---
# Install.sh Update & Helm Deployment Workflow
Complete guide for updating the PraisonAI install script and deploying to Kubernetes via the full CI/CD pipeline.
**⚠️ CRITICAL**: This workflow contains **NO SECRETS**. All sensitive values (tokens, passwords) must be passed via environment variables or external secret management.
## 📁 Key Locations (MUST KNOW)
### Scripts
| File/Resource | Absolute Path | Purpose |
|---------------|---------------|----------|
| **install.sh** | `/Users/praison/praisonai-package/src/praisonai/scripts/install.sh` | Main bash installer |
| **install.ps1** | `/Users/praison/praisonai-package/src/praisonai/scripts/install.ps1` | PowerShell installer |
### CI/CD Pipeline (GitHub → ACR → Helm → K8s)
| File/Resource | Absolute Path | Purpose |
|---------------|---------------|----------|
| **GitHub Workflow** | `/Users/praison/Sites/localhost/praisonai/.github/workflows/azure-pipeline.yaml` | CI/CD pipeline triggered on git push |
| **Dockerfile.php** | `/Users/praison/Sites/localhost/praisonai/Dockerfile.php` | PHP container build |
| **Dockerfile.nginx** | `/Users/praison/Sites/localhost/praisonai/Dockerfile.nginx` | Nginx container build |
| **Dockerfile.init** | `/Users/praison/Sites/localhost/praisonai/Dockerfile.init` | Init container build |
### Helm Deployment
| File/Resource | Absolute Path | Purpose |
|---------------|---------------|----------|
| **Helm Charts** | `/Users/praison/repos/person/helmcharts/` | All Kubernetes deployments |
| **wb_azure Chart** | `/Users/praison/repos/person/helmcharts/charts/wb_azure/` | PraisonAI WordPress deployment |
| **Production Values** | `/Users/praison/Sites/localhost/praisonai/values-praisonai-production.yaml` | Production Helm config |
| **Local Values** | `/Users/praison/Sites/localhost/praisonai/values-local.yaml` | Local development config |
| **Deployment Docs** | `/Users/praison/Sites/localhost/praisonai/DEPLOYMENT.md` | Deployment documentation |
| **Deployment Makefile** | `/Users/praison/Sites/localhost/praisonai/Makefile` | Deployment automation |
---
## 🔄 Full CI/CD Pipeline Overview
```
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Git Push │────▶│ GitHub Actions │────▶│ Azure ACR │
│ (master) │ │ azure-pipeline │ │ Image Build │
└─────────────────┘ └──────────────────┘ └────────┬────────┘
│
▼
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Kubernetes │◀────│ Helm Upgrade │◀────│ Update Image │
│ Deployment │ │ (values.yaml) │ │ Tag in Values │
└─────────────────┘ └──────────────────┘ └─────────────────┘
```
### Pipeline Steps:
1. **Git push** to master branch
2. **GitHub Actions** triggers (`.github/workflows/azure-pipeline.yaml`)
3. **Build** Docker images (nginx, php, init)
4. **Push** to Azure Container Registry (ACR)
5. **Update** Helm values with new image tag
6. **Deploy** using Helm upgrade
---
## 🚀 Phase 0 - Fully Automated CI/CD Pipeline
### Complete Auto-Deploy Architecture
```
Git Push ──▶ Build Images ──▶ Trigger Deploy ──▶ Helm Upgrade ──▶ Production
│ │ │ │
│ ▼ ▼ ▼
│ ACR Push helmcharts wb_azure chart
│ (pa-php:SHA) repository (K8s deploy)
│
└─── install.sh ────────────────────────────────────────────────▶ praison.ai/install.sh
```
### Step 0.1: Build Workflow (Automatic on Git Push)
**File**: `/Users/praison/Sites/localhost/praisonai/.github/workflows/azure-pipeline.yaml`
**Repository**: `https://github.com/MervinPraison/praison.ai`
This workflow triggers on every push to `master`:
```yaml
on:
push:
branches: [master]
```
**What it does:**
1. **Syncs install.sh** from PraisonAI repository (only if changed!)
- Checks out `MervinPraison/PraisonAI`
- Compares `install.sh` and `install.ps1` with existing web files
- **Only copies if files have actually changed** (avoids unnecessary redeploys)
- This ensures `https://praison.ai/install.sh` is always latest
2. Downloads env files from Azure Storage
3. Builds multi-arch Docker images (linux/amd64, linux/arm64)
4. Pushes to Azure Container Registry: `praison.azurecr.io/pa/`
5. **Triggers Helm deployment** via `repository_dispatch` event
**Key Step - Automatic Deploy Trigger:**
```yaml
- name: Trigger Helm Deployment
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
curl -X POST \
-H "Authorization: token ${{ secrets.HELM_REPO_TOKEN }}" \
-d '{
"event_type": "deploy_wb_azure",
"client_payload": {
"image_tag": "'"$SHORT_SHA"'",
"source_repo": "'"${{ github.repository }}"'",
"source_commit": "'"${{ github.sha }}"'"
}
}' \
https://api.github.com/repos/praison/helmcharts/dispatches
```
### Step 0.2: Deploy Workflow (Triggered Automatically)
**File**: `/Users/praison/repos/person/helmcharts/.github/workflows/helm-upgrade-with-image.yml`
Listens for `repository_dispatch` events:
```yaml
on:
repository_dispatch:
types: [deploy_wb_azure, deploy_tcs_azure, deploy_tamilmanna_azure]
```
**What it does:**
1. Receives image tag from build workflow
2. Runs `helm upgrade --install wb_azure` with new image tag
3. Waits for rollout to complete
4. Verifies deployment
**Result**: Every git push automatically builds AND deploys!
### Required GitHub Secrets
For the automated CI/CD to work, you need these secrets configured:
**In praisonai site repository** (`https://github.com/MervinPraison/praison.ai`):
| Secret | Purpose |
|--------|---------|
| `AZURE_CREDENTIALS` | Azure login for ACR and AKS |
| `AZURE_USERNAME` | ACR username |
| `AZURE_PASSWORD` | ACR password |
| `AZURE_STORAGE_KEY` | Download env files from Azure Storage |
| `HELM_REPO_TOKEN` | **NEW**: Trigger deploy workflow in helmcharts repo |
**In helmcharts repository** (`/Users/praison/repos/person/helmcharts/.github/workflows/`):
| Secret | Purpose |
|--------|---------|
| `AZURE_CREDENTIALS` | Azure login for AKS |
| `AKS_CLUSTER_NAME` | Kubernetes cluster name |
| `AKS_RESOURCE_GROUP` | Azure resource group |
**To add HELM_REPO_TOKEN**:
1. Go to GitHub Settings → Developer settings → Personal access tokens
2. Create token with `repo` scope
3. Add as secret `HELM_REPO_TOKEN` in https://github.com/MervinPraison/praison.ai
**Current status**: ✅ Already configured (set via `gh secret set`)!
**Images built:**
- `praison.azurecr.io/pa/pa-nginx:SHORT_SHA`
- `praison.azurecr.io/pa/pa-nginx:master`
- `praison.azurecr.io/pa/pa-php:SHORT_SHA`
- `praison.azurecr.io/pa/pa-php:master`
- `praison.azurecr.io/pa/pa-init:SHORT_SHA`
- `praison.azurecr.io/pa/pa-init:master`
### Step 0.2: Update Helm Values with New Image Tag
After the ACR build completes, update the Helm values file to use the new image:
```bash
cd /Users/praison/Sites/localhost/praisonai
# Get the short SHA from the latest commit (matches the Docker tag)
SHORT_SHA=$(git rev-parse --short HEAD)
# Update values file with new image tag
helm upgrade praisonai /Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--set image.tag=$SHORT_SHA \
--namespace default \
--timeout 10m
```
**Alternative**: Update values file permanently:
```bash
# Edit values-praisonai-production.yaml to set image.tag
sed -i "s/tag: \".*\"/tag: \"$SHORT_SHA\"/" values-praisonai-production.yaml
# Then commit and push the updated values
git add values-praisonai-production.yaml
git commit -m "ci: update image tag to $SHORT_SHA"
git push origin master
```
### Step 0.3: Full Automated Script (For CI/CD Integration)
```bash
#!/bin/bash
# deploy-after-build.sh - Run after ACR build completes
set -e
SHORT_SHA=$(git rev-parse --short HEAD)
NAMESPACE=default
RELEASE_NAME=praisonai
CHART_PATH=/Users/praison/repos/person/helmcharts/charts/wb_azure
VALUES_FILE=/Users/praison/Sites/localhost/praisonai/values-praisonai-production.yaml
echo "🚀 Deploying PraisonAI with image tag: $SHORT_SHA"
# Update Helm deployment with new image tag
helm upgrade --install $RELEASE_NAME $CHART_PATH \
-f $VALUES_FILE \
--set image.tag=$SHORT_SHA \
--namespace $NAMESPACE \
--timeout 10m \
--atomic
echo "✅ Deployment complete!"
echo ""
echo "Verify with:"
echo " kubectl get pods -n $NAMESPACE -l app.kubernetes.io/instance=$RELEASE_NAME"
echo " helm status $RELEASE_NAME -n $NAMESPACE"
```
---
### Step 0.4: Extend GitHub Actions for Automatic Helm Deployment
To make the CI/CD fully automated (build → deploy), extend the GitHub Actions workflow:
**File to edit**: `/Users/praison/Sites/localhost/praisonai/.github/workflows/azure-pipeline.yaml`
Add a new job after the `build` job:
```yaml
deploy:
needs: build # Wait for build to complete
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Setup kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.28.0'
- name: Setup Helm
uses: azure/setup-helm@v3
with:
version: 'v3.13.0'
- name: Get AKS credentials
run: |
az aks get-credentials \
--resource-group your-resource-group \
--name your-aks-cluster-name \
--overwrite-existing
- name: Deploy with Helm
run: |
SHORT_SHA=$(git rev-parse --short HEAD)
helm upgrade --install praisonai \
/Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--set image.tag=$SHORT_SHA \
--namespace default \
--timeout 10m \
--atomic
- name: Verify deployment
run: |
kubectl rollout status deployment/php-nginx -n default
helm status praisonai -n default
```
**Requirements for automatic deploy:**
1. GitHub repository secrets configured:
- `AZURE_CREDENTIALS` - Azure service principal credentials
- `AZURE_STORAGE_KEY` - For downloading env files
- `AZURE_USERNAME` / `AZURE_PASSWORD` - ACR login
2. AKS cluster access configured in Azure
3. Helm and kubectl available in GitHub Actions runner
---
## 🔧 Phase 1 — Update install.sh (Manual, When Needed)
### When to Update
- New PraisonAI version released
- New dependency requirements
- New OS support needed
- Bug fixes in installation process
### Step 1: Read Current install.sh
```bash
# View the install script
cat /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
```
Key sections in install.sh:
- **Lines 1-50**: Header, usage, environment variables documentation
- **Lines 51-150**: OS detection (macOS, Linux, Windows/WSL)
- **Lines 151-300**: Python installation (version checks, package managers)
- **Lines 301-450**: Virtual environment setup
- **Lines 451-550**: PraisonAI package installation
- **Lines 551-637**: PATH configuration, shell integration, verification
### Step 2: Make Changes
**Common Changes:**
#### Update Default Version
```bash
# Find this line (around line 70):
PRAISONAI_VERSION="${PRAISONAI_VERSION:-latest}"
# Change to specific version if needed:
PRAISONAI_VERSION="${PRAISONAI_VERSION:-1.5.0}"
```
#### Add New Environment Variable
```bash
# Add to header section (after line 10, in the comment block):
# PRAISONAI_NEW_FEATURE - Description (default: value)
# Add to actual code (around line 75):
export PRAISONAI_NEW_FEATURE="${PRAISONAI_NEW_FEATURE:-default_value}"
```
#### Update Python Version Requirements
```bash
# Find Python version check (around line 100-120):
PYTHON_MIN_VERSION="3.9"
# Update if needed:
PYTHON_MIN_VERSION="3.10"
```
### Step 3: Test Changes
```bash
# Test locally (dry run)
cd /Users/praison/praisonai-package/src/praisonai/scripts
bash install.sh --dry-run
# Test in Docker (full test)
bash /Users/praison/praisonai-package/src/praisonai/scripts/test-install-smoke.sh
```
### Step 4: Verify Both Scripts
```bash
# Check install.sh syntax
bash -n /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
# Check install.ps1 syntax (if pwsh available)
pwsh -Command "Get-Command /Users/praison/praisonai-package/src/praisonai/scripts/install.ps1"
```
---
## 🚀 Phase 2 — Deploy to Kubernetes (Helm)
### Pre-Deployment Checklist
```bash
# 1. Verify kubectl connection
kubectl get nodes
# 2. Check current Helm releases
helm list -n default
# 3. Verify chart exists
ls /Users/praison/repos/person/helmcharts/charts/wb_azure/
```
### Deployment Types
#### A. Fresh Deployment (First Time)
```bash
cd /Users/praison/Sites/localhost/praisonai
# Option 1: Using Makefile
make deploy
# Option 2: Manual helm command
helm upgrade --install praisonai /Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--namespace default \
--timeout 10m \
--atomic
```
#### B. Update Existing Deployment
```bash
cd /Users/praison/Sites/localhost/praisonai
# Edit values file first
vim values-praisonai-production.yaml
# Then apply
make upgrade
# Or manually:
helm upgrade praisonai /Users/praison/repos/person/helmcharts/charts/wb_azure \
-f values-praisonai-production.yaml \
--namespace default \
--timeout 10m
```
#### C. Local Development Deployment
```bash
cd /Users/praison/Sites/localhost/praisonai
make local-deploy
```
### Values File Structure
```yaml
# /Users/praison/Sites/localhost/praisonai/values-praisonai-production.yaml
# Core settings
replicaCount: 2
# Database
dbHost: "10.0.0.11"
dbUser: "bible_4"
dbPassword: "changeme" # Override via --set
# OpenAI tokens (for plugin verification)
openaiVerificationToken: "token-here"
# Feature toggles
praisonai:
enabled: true
domain: praison.ai
whiteboard:
enabled: true
domain: whiteboard.gallery
# Disable other sites
bible: { enabled: false }
music: { enabled: false }
save: { enabled: false }
# Resources
resources:
requests:
cpu: 800m
memory: 1024Mi
limits:
cpu: 2000m
memory: 2048Mi
# Auto-scaling
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
# Ingress
ingress:
enabled: true
className: nginx
```
---
## 📊 Phase 3 — Verify Deployment
### Check Deployment Status
```bash
# Using Makefile
make status
# Manual checks
helm status praisonai -n default
kubectl get pods -l app.kubernetes.io/instance=praisonai -n default
kubectl get svc -l app.kubernetes.io/instance=praisonai -n default
```
### Verify All Resources
```bash
# Pods should be Running
kubectl get pods -n default | grep praisonai
# Services should be Active
kubectl get svc -n default | grep praisonai
# Ingress should exist
kubectl get ingress -n default | grep praisonai
# ConfigMaps
kubectl get configmap -n default | grep nginx-config
# Secrets
kubectl get secret -n default | grep db-password
```
### Check Application Health
```bash
# Port forward and test
echo "Visit http://127.0.0.1:8080"
kubectl port-forward svc/php-nginx 8080:80 -n default
# In another terminal:
curl http://127.0.0.1:8080/test.php
```
---
## 🔄 Phase 4 — Rollback (If Needed)
```bash
# View revision history
make history
# Rollback to previous revision
make rollback
# Or manually:
helm rollback praisonai 1 -n default
```
---
## 🛠️ Phase 5 — Troubleshooting
### Problem: "Resource exists and cannot be imported"
**Cause**: Existing Kubernetes resources not managed by Helm.
**Solution**: Adopt resources into Helm
```bash
cd /Users/praison/Sites/localhost/praisonai
./scripts/adopt-resources.sh praisonai default
```
Or manually annotate:
```bash
# For any resource type
kubectl annotate <resource-type> <name> \
meta.helm.sh/release-name=praisonai \
meta.helm.sh/release-namespace=default
kubectl label <resource-type> <name> \
app.kubernetes.io/managed-by=Helm
```
### Problem: Pods Not Starting
```bash
# Check events
kubectl get events -n default --sort-by='.lastTimestamp' | tail -20
# Check pod logs
kubectl logs -l app.kubernetes.io/instance=praisonai -n default
# Describe pod for details
kubectl describe pod <pod-name> -n default
```
### Problem: Image Pull Errors
```bash
# Check image pull secrets
kubectl get secret acr-auth -n default
# Verify ACR auth exists
kubectl create secret docker-registry acr-auth \
--docker-server=praison.azurecr.io \
--docker-username=<username> \
--docker-password=<password> \
-n default
```
---
## 📋 Phase 6 — Post-Deployment
### Update Documentation
If install.sh changed, update:
1. `/Users/praison/PraisonAIDocs/docs/installation.mdx` — Installation docs
2. `/Users/praison/praisonai-package/src/praisonai/scripts/README.md` — Script docs (if exists)
### Verify Website
```bash
# Check praison.ai is accessible
curl -I https://praison.ai
# Check whiteboard.gallery
curl -I https://whiteboard.gallery
```
### Monitor
```bash
# Watch pods
kubectl get pods -l app.kubernetes.io/instance=praisonai -n default -w
# Check resource usage
kubectl top pods -l app.kubernetes.io/instance=praisonai -n default
```
---
## 📚 Reference: Helm Chart Structure
```
/Users/praison/repos/person/helmcharts/charts/wb_azure/
├── Chart.yaml # Chart metadata (name: wb, version: 1.0.1)
├── values.yaml # Default values (fallback)
├── templates/
│ ├── deployment.yaml # Main php-nginx deployment
│ ├── service.yaml # NodePort service
│ ├── ingress.yaml # TLS + routing
│ ├── nginx-configMap.yaml # Server configs
│ ├── db-password-secret.yaml # DB credentials
│ ├── pdb.yaml # Pod disruption budget
│ ├── autoscalar.yml # HPA
│ ├── cert-manager.yaml # TLS certificates
│ └── _helpers.tpl # Template helpers
```
---
## 🎯 Quick Commands Reference
| Task | Command |
|------|---------|
| Deploy | `make deploy` |
| Update | `make upgrade` |
| Status | `make status` |
| History | `make history` |
| Rollback | `make rollback` |
| Logs | `make logs` |
| Restart | `make restart` |
| Local dev | `make local-deploy` |
| Dry run | `make dry-run` |
| Lint | `make lint` |
---
## ⚠️ Critical Rules
1. **Never commit SQL dumps**: `.gitignore` already excludes `*.sql` files
2. **Never commit secrets**: Use `--set` or external secret management
3. **Always test install.sh** after changes (use test-install-smoke.sh)
4. **Always verify deployment** with `make status` after Helm operations
5. **Use Infrastructure as Code**: All changes via Helm values files, never manual kubectl
6. **Version control**: Commit values files (without secrets), never commit generated manifests
---
## 🆘 Getting Help
If stuck:
1. Check `/Users/praison/Sites/localhost/praisonai/DEPLOYMENT.md` for detailed docs
2. Check `/Users/praison/Sites/localhost/praisonai/INFRASTRUCTURE_AS_CODE_SUMMARY.md` for quick reference
3. Run `helm status praisonai -n default` for deployment status
4. Run `kubectl get events -n default` for cluster events
5. View install.sh comments for usage examples (lines 1-50)
---
## 🔄 CI/CD Pipeline Summary (For New Agents)
### Complete Workflow (Fully Automated!)
```
Developer Push ──────────────────────────────────────────────▶ Production
│ │
▼ ▼
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ 1. Git Push to │───▶│ 2. GitHub Actions │───▶│ 3. Sync │
│ master │ │ Trigger │ │ install.sh │
└─────────────────┘ └──────────────────┘ └────────┬─────────┘
│
┌────────────────────────┘
▼
┌──────────────────┐
│ 4. Azure ACR │
│ Build Images │
│ + Push │
└────────┬─────────┘
│
──────▶┌──────────────────┐
│ 5. Trigger Deploy│
│ (repository_ │
│ dispatch) │
└────────┬─────────┘
│
┌─────────────────┐ ┌──────────────────┐ │
│ 7. Production │◀───│ 6. Helm Upgrade │◀──┘
│ Running │ │ Deploy │
│ (includes │ │ │
│ install.sh) │ │ │
└─────────────────┘ └──────────────────┘
```
**🎉 Fully Automated**: Git push → Build → Deploy (No manual steps!)
### Automatic install.sh Sync
**Key Point**: The workflow automatically syncs `install.sh` from `MervinPraison/PraisonAI` repository **only if changed**:
```yaml
- name: Checkout PraisonAI for install.sh
uses: actions/checkout@v2
with:
repository: MervinPraison/PraisonAI
path: praisonai-package
- name: Sync install.sh to web folder (if changed)
run: |
# Only sync if files have actually changed
if ! diff -q praisonai-package/src/praisonai/scripts/install.sh ./web/install.sh; then
cp praisonai-package/src/praisonai/scripts/install.sh ./web/install.sh
fi
```
**Optimization**: Uses `diff` to compare files - only copies when install.sh or install.ps1 have actually changed. This avoids unnecessary Docker layer rebuilds and deployments.
**Result**: `https://praison.ai/install.sh` is automatically updated **only when the source files change**!
### How install.sh is Served
The `web/install.sh` file is copied into the Docker image at `/var/www/html/web/install.sh` and served by nginx:
```nginx
# In nginx-config, requests to praison.ai/install.sh
# are served from /var/www/html/web/install.sh
location / {
root /var/www/html/web;
try_files $uri $uri/ =404;
}
```
**URL Mapping**:
| File in Repo | URL |
|--------------|-----|
| `web/install.sh` | `https://praison.ai/install.sh` |
| `web/install.ps1` | `https://praison.ai/install.ps1` |
### What Files to Edit
| To Change | Edit File |
|-----------|-----------|
| Application code | `/Users/praison/Sites/localhost/praisonai/` (PHP files) |
| Docker images | `Dockerfile.php`, `Dockerfile.nginx`, `Dockerfile.init` |
| CI/CD pipeline | `.github/workflows/azure-pipeline.yaml` |
| Helm deployment config | `values-praisonai-production.yaml` |
| Install script | `/Users/praison/praisonai-package/src/praisonai/scripts/install.sh` |
### Common Tasks
**Task 1: Deploy new code**
```bash
cd /Users/praison/Sites/localhost/praisonai
git add .
git commit -m "feat: new feature"
git push origin master
# CI/CD automatically builds and deploys
```
**Task 2: Update install.sh and deploy**
```bash
# 1. Update install.sh
vim /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
# 2. Test install.sh
bash /Users/praison/praisonai-package/src/praisonai/scripts/install.sh --dry-run
# 3. Commit and push
git add /Users/praison/praisonai-package/src/praisonai/scripts/install.sh
git commit -m "fix: update install script"
git push origin main
# 4. Deploy website (if needed)
cd /Users/praison/Sites/localhost/praisonai
make upgrade
```
**Task 3: Rollback deployment**
```bash
cd /Users/praison/Sites/localhost/praisonai
make rollback
# Or: helm rollback praisonai 1 -n default
```
### Architecture
| Layer | Technology | Purpose |
|-------|------------|---------|
| Source Control | Git/GitHub | Code repository |
| CI/CD | GitHub Actions | Automated build/deploy |
| Container Registry | Azure ACR | Docker image storage |
| Orchestration | Kubernetes (AKS) | Container management |
| Deployment | Helm | K8s package management |
| Ingress | NGINX Ingress + cert-manager | Traffic routing + TLS |
### Security Notes
- **No secrets in workflow files** - All tokens/passwords via env vars
- **ACR authentication** - Uses `acr-auth` secret in Kubernetes
- **GitHub Secrets** - `AZURE_CREDENTIALS`, `AZURE_USERNAME`, `AZURE_PASSWORD`
- **Never commit** `.env` files, SQL dumps, or credentials
+181
View File
@@ -0,0 +1,181 @@
---
description: instruction
---
Create multiple TODOs and sub-TODOs, get all things done.
First: detailed analysis, plan, and gap analysis. Go through all files, understand current logic. Search if needed.
Then: implement, fix, test (TDD, Agent-Centric, no perf impact, DRY). praisonaiagents is protocol-driven. Run unit, integration, smoke, and real agentic tests.
After: re-do detailed analysis/plan to find remaining gaps and propose fixes.
Docs: beginner-friendly, for non-developers. Explain concepts with mermaid diagrams (Dark Red #8B0000 for agents/inputs/outputs, Teal #189AB4 for tools, white #fff text). Less descriptive, more interactive. Use Mintlify components: Accordions, Badge, Callouts (Note/Warning/Info/Tip/Check/Danger), Cards/Columns, CodeGroup, Expandables, Tabs, Steps, Frame, Icon, Tooltip, Mermaid, ParamField, Tables, CardGroup.
You are an expert AI engineer in the PraisonAI ecosystem.
Production-quality code, zero regressions, full verification. Make PraisonAI the best agent framework.
### Core Philosophy
```
Simpler • More extensible • Faster • Agent-centric
```
| Principle | Rule |
|---|---|
| Agent-Centric | Design centers on Agents, workflows, sessions, tools, memory |
| Protocol-Driven | Core SDK: protocols/hooks/adapters only; heavy code in wrapper/tools |
| Minimal API | Fewer params, sensible defaults, explicit overrides |
| Performance-First | Lazy loading, optional deps, no hot-path regressions |
| Production-Ready | Safe by default, multi-agent safe, async-safe |
- Powerful, lightweight, reliable. Easy for non-developers.
- "Few lines of code to do the task!" — SDK and docs must feel this way.
- Each feature runs 3 ways: CLI, YAML, Python.
- Open source, developer-first. Core free, clear upgrade path to paid (support/cloud/services).
- Simple to adopt, hard to misuse, safe by default.
- Prioritise time saved, reduced risk, and operational confidence.
- Reduce production friction, not just add functionality.
- All features must have CLI integration. Agent-first naming and ergonomics.
ENGINEERING PRINCIPLES (MUST)
- DRY: reuse abstractions, no duplication.
- Protocol-driven core: protocols/hooks in core; heavy impl in wrapper/tools.
- No perf impact: lazy imports, optional deps, no global singletons, no heavy module-level work.
- TDD mandatory: tests first.
- Multi-agent + async safe by default.
- AGENTS.md is not for documentation.
CRITICAL REQUIREMENTS
- EXECUTE + VERIFY mode. No guessing. Proof for "done."
- Optional deps only; lazy import everything heavy.
- Every feature/fix: Python + CLI + docs/examples.
- Any core change must be justified: simpler client API, measurable benefit, NO perf regression.
- If TypeScript parity required: update praisonai-ts, but never at cost of Python core performance.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CANONICAL PATHS (MUST use these)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
- Core SDK: /Users/praison/praisonai-package/src/praisonai-agents → praisonaiagents
- Wrapper: /Users/praison/praisonai-package/src/praisonai → praisonai
- Tools: /Users/praison/PraisonAI-tools → praisonai-tools
- Docs: /Users/praison/PraisonAIDocs (read AGENTS.md first before updating docs)
- Docs JS: /Users/praison/PraisonAIDocs/docs/js | Rust: docs/rust
- Examples: /Users/praison/praisonai-package/examples/
- TypeScript: /Users/praison/praisonai-package/src/praisonai-ts
- Rust: /Users/praison/praisonai-package/src/praisonai-rust (follow praisonai-ts/AGENTS.md)
- UI (this repo): /Users/praison/praisonaiui → praisonaiui
- Extension points: tools/base.py, tools/decorator.py, db/*
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
ARCHITECTURE
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Core (praisonaiagents): protocol-driven, lightweight. No heavy imports. Only protocols/hooks/adapters.
Wrapper (praisonai): real integrations (DBs, observability, CLI). Lazy imports, optional deps.
Tools (PraisonAI-tools): pluggable, never overload core/wrapper.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
MANDATORY EXECUTION FLOW
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PHASE 1 — ANALYSIS (before writing code)
1.1 Acceptance Criteria — testable bullets for API, CLI, docs, tests, perf.
1.2 Repo Inventory — scan relevant files end-to-end:
- modules/classes/APIs/exports, CLI commands, tests, docs/examples
- Evidence: paths + symbols + grep counts. Identify DRY opportunities.
1.3 Gap Analysis — what exists vs what's needed:
- Missing: core SDK, wrapper, tools, CLI, docs, tests, exports
- Risks: perf, API breaks, optional deps, async, multi-agent
1.4 Report — current behavior, pain points, root causes (file refs), constraints, risk register, decision log.
1.5 Plan — step-by-step: tests → impl → CLI → docs → verify. Files to change. Compat/rollback/perf strategy.
1.6 Proposal — minimal agent-centric design. Protocols in core, impl in wrapper. Upgrade-path notes.
1.7 TODO Tree — granular, executable. Python + CLI + TDD + docs + perf.
- Second-to-last: "Verify all changes end-to-end"
- Last: "Implement remaining gaps (missing=0), re-verify" or "Final scan, confirm missing=0"
PHASE 2 — EXECUTE
2.1 TDD — write failing tests first. Deterministic and fast.
2.2 Implement — DRY, agent-centric, protocol-driven. Heavy code in wrapper/tools. Multi-agent + async safe.
2.3 CLI parity — add/extend CLI commands. Scriptable, clear help, proper exit codes.
2.4 Docs — Mintlify pages (SDK="Module", API="API"). Copy-paste runnable examples.
2.5 Verification:
- Run tests (unit/integration), show results.
- Smoke: `python3 -c "..."` + CLI help/run.
- Optional deps graceful degradation.
- Perf: no heavy core imports, import-time sanity.
- Provide evidence for every claim.
- dont use Sending termination request to command to terminate a process, kill port instead when terminating
REAL AGENTIC TEST (MANDATORY — not replaceable by smoke tests)
- After unit/smoke tests, MUST run at least one REAL agent execution:
1. Create Agent with the feature being tested
2. Call `agent.start("a real task prompt")` — NOT just constructing the object
3. Agent MUST call LLM and produce text response
4. Print full output so dev can see it worked end-to-end
- Minimum example:
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are a helpful assistant")
result = agent.start("Say hello in one sentence")
print(result)
```
- Assert-only object construction = SMOKE TEST, not real agentic test.
- Both smoke AND real agentic tests required.
PHASE 3 — POST-IMPLEMENTATION ANALYSIS
3.1 Re-scan files, summarize final behavior/architecture.
3.2 Confirm remaining gaps (API, CLI, docs, tests, exports, perf, multi-agent, async). If gaps exist, treat as required work until missing=0.
3.3 Report: what changed, why, validation evidence, tradeoffs.
3.4 Plan: close remaining gaps or maintenance plan.
3.5 Proposal: refinements for UX, safety, perf, extensibility. Label: implemented vs out-of-scope.
Final rule: conclude only when evidence shows missing = 0.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
PUBLISH WORKFLOW (reference)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
GitHub Actions (recommended):
GitHub → Actions → "PyPI Release" → Run workflow → bump: patch
Requires repo secrets: PYPI_TOKEN, GH_TOKEN
Requires GitHub Environment "pypi" with required reviewers (Settings → Environments)
Manual — Publish aiui (PraisonAIUI):
cd /Users/praison/PraisonAIUI
# Bump version in pyproject.toml and src/praisonaiui/__version__.py
rm -rf dist && uv lock && uv build && uv publish --token "$PYPI_TOKEN"
git add pyproject.toml uv.lock src/praisonaiui/__version__.py
git commit -m "Release vX.Y.Z" && git tag vX.Y.Z && git push && git push --tags
gh release create vX.Y.Z --title "PraisonAIUI vX.Y.Z" --notes "Release vX.Y.Z" --latest
PyPI package name: aiui
Verify: pip index versions aiui | head -1
PraisonAI stack (separate repo — publish SDK before wrapper):
cd /Users/praison/praisonai-package/src/praisonai-agents
praisonai publish pypi
# Uses uv internally: uv lock → uv build → uv publish
# Auto-bumps patch version, requires PYPI_TOKEN env var
Step 2 — Publish praisonai (Wrapper):
cd /Users/praison/praisonai-package/src/praisonai
python scripts/bump_and_release.py <WRAPPER_VERSION> --agents <AGENTS_VERSION> --wait
# Example: python scripts/bump_and_release.py 4.5.90 --agents 1.5.91 --wait
# Waits for agents to be available on PyPI, bumps all version files,
# runs uv lock, builds, commits, tags, pushes, creates GitHub release
# Then: uv publish (from src/praisonai with clean dist/)
If bump_and_release published already, just verify:
pip index versions praisonai | head -1
If uv publish fails with "File already exists", it means the version is already on PyPI — success.
Step 3 — Publish praisonai-tools (External, if needed):
cd /Users/praison/PraisonAI-tools
# Bump version in pyproject.toml, then:
python3.13 -m build && uv run twine upload dist/*
PraisonAI PRs: NEVER merge automatically — user merges manually.
+223
View File
@@ -0,0 +1,223 @@
---
description: Implement, fix, and test code changes locally — for when the agent IS the implementer
---
# Local Fix Workflow
You are the implementer. Analyze → Plan → Implement → Test → Verify → PR.
> **When to use this:** The user explicitly asks you to fix something locally, or delegates a task that cannot be handled by the GitHub cloud agents.
> **When NOT to use this:** If given an Issue URL, prefer `@[/pr-review]` Step 8d — delegate to cloud agents first.
---
## Phase 1 — Analysis (before writing ANY code)
### 1a. Understand the problem
// turbo
```bash
cd /Users/praison/praisonai-package && git checkout main && git pull origin main
```
Read all relevant source files end-to-end. Use `grep`, `view_file`, and code navigation.
- Identify root cause with **file paths and line numbers**
- Trace the full code path (caller → callee → side effects)
- Assess blast radius (what else could break)
- Check for existing abstractions before creating new ones (DRY)
### 1b. Create TODO tree
Break work into granular, executable items:
```
- [ ] Write failing test(s)
- [ ] Implement fix (file:line references)
- [ ] CLI parity (if applicable)
- [ ] Docs update (if applicable)
- [ ] Run unit + integration tests
- [ ] Run real agentic test
- [ ] Verify end-to-end
```
---
## Phase 2 — Implement
### 2a. TDD — tests first
Write the failing test before touching implementation code.
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/<relevant_test>.py -x -v --tb=short
```
### 2b. Implement the fix
**Architecture rules (MUST follow):**
| Layer | What goes here | What does NOT go here |
|-------|---------------|----------------------|
| **Core SDK** (`praisonaiagents/`) | Protocols, hooks, adapters, base classes, decorators, dataclasses | Heavy implementations, optional deps at module level |
| **Wrapper** (`praisonai/`) | CLI commands, integrations, heavy impls, DB adapters, UI | Core logic |
| **Tools** (`PraisonAI-tools/`) | Pluggable tools, community extensions | Core or wrapper logic |
**Coding standards:**
- **Lazy imports**: Optional deps imported inside functions, never at module level
- **DRY**: Reuse existing abstractions; refactor if duplication found
- **Naming**: `add_X()`, `get_X()`, `XConfig`, `XProtocol`, `XAdapter`
- **Async-safe**: No blocking I/O in async context; use asyncio primitives
- **Multi-agent safe**: No shared mutable globals without `threading.Lock`
- **Security**: No hardcoded secrets; `hmac.compare_digest` for comparisons; sandboxed `exec()`
- **Backward compat**: Public API changes require deprecation cycle
**Canonical paths:**
| What | Where |
|------|-------|
| Core SDK | `/Users/praison/praisonai-package/src/praisonai-agents/praisonaiagents/` |
| Wrapper | `/Users/praison/praisonai-package/src/praisonai/praisonai/` |
| Tools | `/Users/praison/PraisonAI-tools/` |
| Docs | `/Users/praison/PraisonAIDocs/` (read AGENTS.md first) |
| Examples | `/Users/praison/praisonai-package/examples/` |
| TypeScript | `/Users/praison/praisonai-package/src/praisonai-ts/` |
### 2c. CLI parity
Every feature must work 3 ways: **Python, CLI, YAML**. If your change adds or modifies a feature, ensure CLI support exists.
---
## Phase 3 — Test & Verify
### 3a. Unit + Integration tests
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/ -x -q \
--ignore=tests/integration/test_whatsapp_web_real.py \
--ignore=tests/unit/tools/test_profiles.py \
--tb=short 2>&1 | tail -20
```
### 3b. Real agentic test (MANDATORY)
Unit tests alone are NOT sufficient. You MUST run at least one real agent execution:
```python
from praisonaiagents import Agent
agent = Agent(name="test", instructions="You are a helpful assistant")
result = agent.start("Say hello in one sentence")
print(result)
```
**Rules:**
- Agent MUST call `agent.start()` with a real prompt
- Agent MUST call the LLM and produce a text response
- Print full output — assert-only object construction is a SMOKE test, not agentic
- Both smoke AND real agentic tests required
### 3c. Security checks (if touching sensitive code)
```bash
# Hardcoded secrets
grep -rn "secret\|password\|token\|api_key" --include="*.py" <changed-files> | \
grep -v "test_\|#\|environ\|getenv\|config"
# Timing attacks
grep -rn "==.*api_key\|==.*secret\|==.*token" --include="*.py" <changed-files>
# Sandbox escapes
grep -rn "exec(\|eval(" --include="*.py" <changed-files>
```
### 3d. Performance sanity
```bash
# Verify no heavy imports at module level
python -c "import time; t=time.time(); import praisonaiagents; print(f'{(time.time()-t)*1000:.0f}ms')"
```
Target: < 200ms package import time.
---
## Phase 4 — Post-implementation scan
Re-scan changed files. Confirm:
- [ ] No remaining gaps (API, CLI, docs, tests, exports, perf)
- [ ] No regressions introduced
- [ ] All acceptance criteria met with evidence
If gaps remain → loop back to Phase 2. Conclude only when `missing = 0`.
---
## Phase 5 — Submit
### 5a. Create branch and PR
```bash
cd /Users/praison/praisonai-package && \
git checkout -b <type>/<descriptive-name> && \
git add -A && \
git commit -m "<type>: <description>" && \
git push origin <type>/<descriptive-name>
```
```bash
cd /Users/praison/praisonai-package && \
gh pr create \
--title "<type>: <description>" \
--body '## Summary
<what and why>
### Changes
- <file>: <what changed>
### Testing
- Unit tests: ✅
- Agentic test: ✅
- Security: ✅ (if applicable)' \
--head <type>/<descriptive-name> \
--base main
```
**Commit prefixes:** `fix:`, `feat:`, `security:`, `refactor:`, `docs:`, `test:`
> **Do NOT merge automatically** — user merges manually unless explicitly told otherwise.
### 5b. Verify PR state
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr view --json state,title,url | cat
```
---
## Publish (only when user requests)
```bash
# Core SDK
cd /Users/praison/praisonai-package/src/praisonai-agents && praisonai publish pypi
# Wrapper
cd /Users/praison/praisonai-package/src/praisonai && \
python scripts/bump_and_release.py <VERSION> --agents <AGENTS_VERSION> --wait
```
---
## Quick Reference — Red Flags
| Red Flag | Fix |
|----------|-----|
| Module-level `import chromadb` | Move inside function with `try/except ImportError` |
| `exec(user_input)` without sandbox | Use `RestrictedPython` or sandbox module |
| `if token == secret:` | Use `hmac.compare_digest(token, secret)` |
| Shared mutable global `_cache = {}` | Add `threading.Lock`, or make per-agent |
| `debug=True` in production path | Remove or gate behind env var |
| Missing `async` variant for I/O | Add async version, wrap for sync callers |
+275
View File
@@ -0,0 +1,275 @@
---
description: Review, validate, and merge GitHub pull requests or triage issues
---
# PR / Issue Review Workflow
When given a GitHub PR or Issue URL, follow this procedure end-to-end.
---
## Step 0 — Determine Type
Parse the URL to identify whether it is a **Pull Request** or an **Issue**.
```
https://github.com/MervinPraison/PraisonAI/pull/<NUMBER> → PR
https://github.com/MervinPraison/PraisonAI/issues/<NUMBER> → Issue
```
- **PR** → go to Step 1
- **Issue** → go to Step 8
---
## Step 1 — Fetch PR Metadata
// turbo
```bash
cd /Users/praison/praisonai-package && \
gh pr view <NUMBER> --json title,body,author,state,additions,deletions,changedFiles,headRefName,baseRefName,labels
```
Record: title, author, branch, file count, +/- lines.
---
## Step 2 — Read the Full Diff
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr diff <NUMBER>
```
If the diff is very large (>500 lines), pipe through `head -500` first, then read remaining chunks.
---
## Step 3 — Review the Diff
For each changed file, evaluate against **PraisonAI engineering principles** (from AGENTS.md):
| Principle | What to Check |
|-----------|---------------|
| **Protocol-driven core** | No heavy implementations in `praisonaiagents/` (core SDK) |
| **Lazy imports** | Optional deps imported inside functions, not at module level |
| **DRY** | No code duplication; reuse existing abstractions |
| **Naming conventions** | `add_X()`, `get_X()`, `XConfig`, `XProtocol`, `XAdapter` |
| **Async-safe** | No blocking I/O in async context; asyncio primitives used |
| **Multi-agent safe** | No shared mutable global state without locks |
| **Thread safety** | Double-checked locking for lazy caches; `threading.Lock` for mutables |
| **Security** | No hardcoded secrets; `hmac.compare_digest` for comparisons; restricted `exec()` |
| **Backward compat** | Public API changes require deprecation cycle |
| **Test coverage** | Tests included; TDD pattern; both unit + agentic tests |
**Red flags to catch:**
- Module-level imports of optional deps (chromadb, litellm, etc.)
- Hardcoded credentials or `debug=True` in production paths
- Direct string comparison for secrets (timing attacks)
- `exec()`/`eval()` without sandbox
- Shared mutable globals without `threading.Lock`
- Missing error handling or swallowed exceptions
---
## Step 4 — Checkout and Run Tests Locally
// turbo
```bash
cd /Users/praison/praisonai-package && git checkout main && git pull origin main
```
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr checkout <NUMBER>
```
Run targeted tests for changed files first:
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/ -x -q \
--ignore=tests/integration/test_whatsapp_web_real.py \
--ignore=tests/unit/tools/test_profiles.py \
--tb=short 2>&1 | tail -20
```
For PRs touching security-sensitive code, also run:
```bash
# Sandbox tests
python -m pytest tests/unit/tools/test_python_tools_sandbox.py -v
# CWE-78 env injection tests
python -m pytest src/praisonai/tests/unit/test_cwe78_env_injection.py -v
# Thread-safety tests
python -m pytest tests/unit/test_thread_safety.py -v
```
---
## Step 5 — Verify No Regressions
Run the full test suite:
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && \
python -m pytest tests/ -q \
--ignore=tests/integration/test_whatsapp_web_real.py \
--ignore=tests/unit/tools/test_profiles.py \
--tb=no 2>&1 | tail -5
```
**Acceptable result:** All tests pass, or only pre-existing flaky tests fail (e.g., `test_file_memory.py::test_memory_persistence_across_agent_instances`).
**Unacceptable:** Any NEW failure introduced by the PR.
---
## Step 6 — Approve or Request Changes
**If the PR is good:**
```bash
cd /Users/praison/praisonai-package && \
gh pr review <NUMBER> --approve --body "LGTM — reviewed diff, tests pass, follows PraisonAI engineering principles."
```
**If changes are needed:**
```bash
cd /Users/praison/praisonai-package && \
gh pr review <NUMBER> --request-changes --body "Requesting changes: <specific feedback>"
```
---
## Step 7 — Merge
```bash
cd /Users/praison/praisonai-package && \
gh pr merge <NUMBER> --merge --subject "<PR title>"
```
Verify merge:
// turbo
```bash
cd /Users/praison/praisonai-package && gh pr view <NUMBER> --json state,mergedAt
```
Then return to main:
// turbo
```bash
cd /Users/praison/praisonai-package && git checkout main && git pull origin main
```
---
## Step 8 — Issue Triage (if URL is an Issue)
### 8a. Fetch issue details
// turbo
```bash
cd /Users/praison/praisonai-package && \
gh issue view <NUMBER> --json title,body,author,state,labels,comments
```
### 8b. Classify severity
| Tier | Criteria | Examples |
|------|----------|---------|
| **Tier 1 — Critical** | Security vuln, data loss, crash in hot path | exec() without sandbox, hardcoded secrets, unprotected globals |
| **Tier 2 — High** | Performance regression, broken feature, wrong output | Duplicate API calls, memory leak, silent failure |
| **Tier 3 — Medium** | DX issue, missing validation, doc gap | Bad error messages, missing CLI parity, stale docs |
| **Tier 4 — Low** | Cosmetic, code style, minor refactor | Trailing whitespace, naming inconsistency |
### 8c. Deep analysis (for Tier 1-2)
1. Read ALL relevant source files end-to-end
2. Trace the code path that the issue describes
3. Identify root cause with file paths and line numbers
4. Assess blast radius (what else could be affected)
5. Determine if the issue is **actually what it claims** (re-classify if needed)
### 8d. Delegate Implementation to GitHub Workflow Agents
> **KEY PHILOSOPHY: We act as the Manager, GitHub Actions execute the Workflow.**
**DO NOT implement the fix yourself locally.** PraisonAI uses autonomous GitHub Action workflows (such as `gemini-issue-review.yml` and `claude.yml`) to automatically resolve issues and create PRs. Your job as the local agent is to supervise, analyze gaps, and trigger these cloud agents to do the heavy lifting. If there is a gap (e.g. strict test violations), provide detailed relevant information in the PR/Issue and trigger the agents again.
1. Issue the command to trigger the cloud agent on the issue:
```bash
cd /Users/praison/praisonai-package && \
gh issue comment <NUMBER> --body "@gemini please review and fix this issue"
```
*(Note: You can use `@claude` or `@gemini` depending on preference or active bots).*
2. Check the GitHub Actions logs (`gh run list`) and wait for the cloud agent to open a Pull Request (`gh pr list`).
3. Once the cloud bot opens a Pull Request for the issue, return to **Step 1** to review the PR, test the branch locally, and merge it if it passes the checks.
---
## Step 9 — (Skipped) Local PR Creation
> **Note:** As the local agent, you should delegate code fixes to the cloud agents. Only implement code locally and create a PR if the USER explicitly forces you to bypass the cloud agents. If forced, use standard prefixes: `fix:`, `feat:`, `security:`, `refactor:`, `docs:`, `test:`.
---
## Step 10 — Security-Specific Checks
When reviewing security-related PRs, additionally verify:
### Credentials / Secrets
```bash
# Check for hardcoded secrets
grep -rn "secret\|password\|token\|api_key" --include="*.py" <changed-files> | \
grep -v "test_\|#\|environ\|getenv\|config"
```
### Timing Attacks
```bash
# Ensure hmac.compare_digest for secret comparisons
grep -rn "==.*api_key\|==.*secret\|==.*token" --include="*.py" <changed-files>
```
### Authentication & Workflow Secrets
When reviewing GitHub Actions workflows (especially ones using cloud actions like `claude-code-action`):
- **OIDC Validation**: Any workflow using OIDC to authenticate with a cloud provider (e.g. AWS Bedrock for Claude, GCP for Vertex) **MUST** include `id-token: write` in the job's `permissions`. Without it, you will see `Could not fetch an OIDC token` errors.
- **Valid PAT Usage**: When injecting tokens into workflows via `github_token:`, ensure you use `secrets.GH_TOKEN`. `secrets.PAT_TOKEN` has been known to be invalid or cause `401 Bad credentials` errors when curling GitHub resources. By design, `@copilot` mentions also strictly require `GH_TOKEN`.
### Supply Chain
```bash
# Check dependency versions
pip show <package-name>
# Check for known compromised versions
pip install <package>==999 2>&1 | grep "from versions"
```
### IoC Scanning
```bash
# Check for known malicious files
find $(python -c "import site; print(site.getsitepackages()[0])") -name "<suspicious-file>" 2>/dev/null
```
---
## Quick Reference — Common Commands
| Action | Command |
|--------|---------|
| View PR | `gh pr view <N> --json title,body,state,additions,deletions` |
| View diff | `gh pr diff <N>` |
| Checkout PR | `gh pr checkout <N>` |
| List open PRs | `gh pr list` |
| List open issues | `gh issue list` |
| View issue | `gh issue view <N>` |
| Approve PR | `gh pr review <N> --approve` |
| Request changes | `gh pr review <N> --request-changes --body "..."` |
| Merge PR | `gh pr merge <N> --merge` |
| Create PR | `gh pr create --title "..." --body "..." --head <branch> --base main` |
| Run tests | `cd src/praisonai-agents && python -m pytest tests/ -q --tb=no` |
| Check dep version | `pip show <package>` |
+219
View File
@@ -0,0 +1,219 @@
---
description: Publish and release praisonaiagents + praisonai to PyPI (default = hotfix patch)
---
// turbo-all
# Publish & Release Workflow
End-to-end publish pipeline for the PraisonAI stack. **Default release type is a hotfix (patch) bump.** Only three commands are needed — each does the heavy lifting. The wrapper is uploaded to PyPI automatically by GitHub Actions once the release is created.
## Packages & version rules
| Package | Canonical path | Current family |
|---|---|---|
| `praisonaiagents` (Core SDK) | `/Users/praison/praisonai-package/src/praisonai-agents` | `1.6.x` |
| `praisonai` (Wrapper) | `/Users/praison/praisonai-package/src/praisonai` | `4.6.x` |
- Wrapper **major.minor** tracks the SDK: SDK `1.6.x` ↔ wrapper `4.6.x`.
- **Patch numbers must match** across both packages for the same release (SDK `1.6.9` ↔ wrapper `4.6.9`).
- Working branch: `main` — push directly, no feature branches.
## Prerequisites
- PyPI token in `/Users/praison/.pypirc` under `[pypi].password` (format `pypi-...`).
- `gh` CLI authenticated (`gh auth status`).
- Working tree on `main` with the code change already in place (uncommitted is fine — step 2 will auto-commit).
Export the PyPI token once for the session:
```bash
export PYPI_TOKEN=$(python3 -c "import configparser;c=configparser.ConfigParser();c.read('/Users/praison/.pypirc');print(c['pypi']['password'])")
```
---
## STEP 1 — Publish `praisonaiagents` (Core SDK)
**`praisonai publish pypi` run from inside `praisonai-agents/` automatically:**
1. Reads the current version from `pyproject.toml`
2. Auto-bumps the **patch** number (default; use `--minor` / `--major` to override)
3. Runs `rm -rf dist && uv lock && uv build && uv publish --token $PYPI_TOKEN`
4. Publishes the package to PyPI
// turbo
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents
praisonai publish pypi
```
Bump variants (optional):
- `praisonai publish pypi --minor` → `1.6.9 → 1.7.0`
- `praisonai publish pypi --major` → `1.6.9 → 2.0.0`
- `praisonai publish pypi --no-bump` → publish current version
- `praisonai publish pypi --dry-run` → preview without executing
Verify:
```bash
pip index versions praisonaiagents | head -1
```
> Note the new SDK version (e.g. `1.6.9`) — you'll need it in step 3.
---
## STEP 2 — Auto-commit the version bump
**`praisonai commit -a` automatically:**
1. Stages all changes (`-a`)
2. Generates an AI commit message
3. Creates the commit
Add `-p` / `--push` to also push to origin in one shot.
// turbo
```bash
cd /Users/praison/praisonai-package
praisonai commit -a -p
```
Equivalent flags:
- `praisonai commit -a` — commit only
- `praisonai commit -a -p` — commit + push (recommended for releases)
- `praisonai commit -a -m "chore: bump praisonaiagents to 1.6.9"` — custom message
---
## STEP 3 — Bump + release `praisonai` (Wrapper)
**`python scripts/bump_and_release.py <WRAP_VERSION> --agents <AGENTS_VERSION> --wait` automatically:**
1. Waits for the SDK version to propagate on PyPI (`--wait`)
2. Updates every version file:
- `src/praisonai/praisonai/version.py`
- `src/praisonai/praisonai/deploy.py`
- `src/praisonai/pyproject.toml` (wrapper version + `praisonaiagents` dependency)
- `docker/Dockerfile{,.chat,.dev,.ui}`
- `src/praisonai/praisonai.rb` (Homebrew formula)
3. Copies root `README.md` into the package
4. Runs `uv cache clean → uv lock → uv build`
5. Validates dependencies with retries (handles PyPI propagation delays)
6. `git add -A && git commit -m "Release vX.Y.Z"`
7. Creates & force-pushes tag `vX.Y.Z`
8. `git pull --rebase origin main && git push && git push --tags -f`
9. `gh release create vX.Y.Z --latest` → this triggers the `.github/workflows/python-publish.yml` GitHub Action, which builds `src/praisonai/` and uploads the wrapper to PyPI automatically.
**Version rule:** wrapper patch = SDK patch. If SDK became `1.6.9`, wrapper becomes `4.6.9`.
```bash
cd /Users/praison/praisonai-package/src/praisonai
python scripts/bump_and_release.py 4.6.9 --agents 1.6.9 --wait
```
Template:
```bash
python scripts/bump_and_release.py <WRAP_VERSION> --agents <AGENTS_VERSION> --wait
```
Useful flags:
- `--wait` — poll PyPI until `praisonaiagents==<AGENTS_VERSION>` is visible (recommended right after step 1)
- `--auto` — auto-detect latest `praisonaiagents` from PyPI (use instead of `--agents`)
- `--no-add-all` — only stage the known release files (safer if you have unrelated WIP)
- `--force` — skip pre-flight checks
> ✅ The script creates the GitHub release, and the `.github/workflows/python-publish.yml` Action automatically uploads the wrapper to PyPI. **No manual `uv publish` needed.**
Watch the Action run:
```bash
gh run watch --exit-status --repo MervinPraison/PraisonAI
```
---
## Post-release checks
// turbo
```bash
pip index versions praisonaiagents | head -1
pip index versions praisonai | head -1 # may take ~1–2 min for GH Actions to publish
gh release view v<WRAPPER_VERSION> --json tagName,isLatest,url
gh run list --workflow=python-publish.yml --limit 3
cd /Users/praison/praisonai-package && git log --oneline -5
```
---
## One-shot hotfix (copy/paste)
Replace `AGENTS_NEW` and `WRAP_NEW` with the next patch pair (same last number):
```bash
export PYPI_TOKEN=$(python3 -c "import configparser;c=configparser.ConfigParser();c.read('/Users/praison/.pypirc');print(c['pypi']['password'])")
# 1. Publish SDK (auto-bumps patch, builds, uploads to PyPI)
cd /Users/praison/praisonai-package/src/praisonai-agents
praisonai publish pypi
# 2. Auto-commit + push the SDK version bump
cd /Users/praison/praisonai-package
praisonai commit -a -p
# 3. Bump + tag + release the wrapper. GitHub Actions publishes it to PyPI.
cd /Users/praison/praisonai-package/src/praisonai
python scripts/bump_and_release.py WRAP_NEW --agents AGENTS_NEW --wait
# 4. Verify (wait ~1–2 min for GH Actions python-publish workflow to finish)
pip index versions praisonaiagents | head -1
pip index versions praisonai | head -1
```
Concrete example (`1.6.9` / `4.6.9`):
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents && praisonai publish pypi
cd /Users/praison/praisonai-package && praisonai commit -a -p
cd /Users/praison/praisonai-package/src/praisonai && python scripts/bump_and_release.py 4.6.9 --agents 1.6.9 --wait
```
---
## Troubleshooting
- **`uv publish` 403 / missing token (SDK step only)** — `PYPI_TOKEN` not exported; re-run the `export PYPI_TOKEN=…` line from Prerequisites.
- **Wrapper didn't appear on PyPI** — the GH Action may have failed. Check it:
```bash
gh run list --workflow=python-publish.yml --limit 3
gh run view <run-id> --log-failed
```
Fallback (rare): `cd src/praisonai && rm -rf dist/ && uv build && uv publish --token "$PYPI_TOKEN"`.
- **`gh release create` fails inside `bump_and_release.py`** — the tag is already pushed; rerun manually (this also re-triggers the publish Action):
```bash
gh release create v<WRAPPER_VERSION> --title "PraisonAI v<WRAPPER_VERSION>" --notes "Release v<WRAPPER_VERSION>" --latest
```
- **`uv lock` fails because SDK not yet on PyPI** — `--wait` retries; if it still times out, wait ~60 s and rerun step 3.
- **Wrong branch** — releases must ship from `main`. Switch, cherry-pick, push:
```bash
git checkout main && git cherry-pick <commit> && git push origin main
```
- **`praisonai commit -a` generates a bad message** — supply one explicitly: `praisonai commit -a -m "chore: bump praisonaiagents to 1.6.9" -p`.
---
## Rules
- ALWAYS publish the **SDK first**, then the wrapper (the wrapper pins the SDK version).
- ALWAYS keep the **patch number identical** across both packages.
- ALWAYS release from `main` — never a feature branch.
- ALWAYS use `--wait` in step 3 so the wrapper's `uv lock` can resolve the new SDK.
- ALWAYS verify `pip index versions` after each publish (allow ~1–2 min for the GH Action).
- NEVER edit `version.py`, Dockerfiles, or `praisonai.rb` by hand — `bump_and_release.py` owns them.
- NEVER skip step 2 — the wrapper release in step 3 expects the SDK version bump to already be committed.
- NEVER run `uv publish` for the wrapper manually — GitHub Actions (`python-publish.yml`) owns that step.
---
## Resources
- **Repository**: https://github.com/MervinPraison/PraisonAI
- **Documentation**: https://docs.praison.ai
- **Website**: https://praison.ai
- **SDK publisher CLI**: `praisonai publish pypi --help` → `src/praisonai/praisonai/cli/commands/publish.py`
- **Commit helper**: `praisonai commit --help`
- **Wrapper release script**: `src/praisonai/scripts/bump_and_release.py`
- **Wrapper PyPI publish Action**: `.github/workflows/python-publish.yml` (triggers on `release: published`)
+58
View File
@@ -0,0 +1,58 @@
---
description: PR review chain — how automated reviews flow for every PR
---
## Review Chain (Sequential)
> **KEY PHILOSOPHY: We act as the Manager, GitHub Actions execute the Workflow.**
> As the local agent, our job is to analyze, supervise, and coordinate the cloud bots. If we identify a gap in the review chain or code (e.g., missing tests), provide detailed relevant information and trigger the agents (like `@claude`) again.
```
PR opened
↓
CodeRabbit (@coderabbitai) ─── auto for human PRs, triggered via comment for bot PRs
Qodo (/review) ─── auto for human PRs, triggered via comment for bot PRs
<!-- Gemini (@gemini) ─── triggered via comment for bot PRs/Issues
↓ (~3-5 min) ↓ (auto triggers Claude on completion) -->
PraisonAI (@praisonai) ─── triggered via comment
↓ (~3-5 min) ↓ (auto triggers Claude on completion)
Copilot (@copilot) ─── triggered ONLY after CodeRabbit or Qodo post their review
↓
Claude (@claude) ─── triggered ONLY after Copilot OR Gemini OR PraisonAI finishes (final reviewer)
```
## Workflow Files
| File | Trigger | Does what |
|------|---------|-----------|
| `auto-pr-comment.yml` | `issue_comment`, `pull_request_review`, `pull_request:opened` | Triggers Copilot after CodeRabbit/Qodo finish. For bot PRs: triggers CodeRabbit+Qodo+Gemini first. |
| `praisonai-pr-review.yml` | `issue_comment`, `workflow_dispatch` | PraisonAI multi-agent PR review triggered by @praisonai mentions. |
| `chain-claude-after-copilot.yml` | `pull_request_review:submitted`, `issue_comment` | Triggers Claude after Copilot reviews, AND automatically after Gemini Code Assist finishes fixing issues/PRs. |
| `claude.yml` | `issue_comment`, `pull_request_review_comment`, `issues:assigned/labeled` | Claude responds to @claude mentions. |
## Bot PR fix
CodeRabbit and Qodo skip `github-actions[bot]` authored PRs by default. The `bot-pr-trigger-reviews` job in `auto-pr-comment.yml` explicitly triggers them via comments.
## PraisonAI Integration
PraisonAI provides multi-agent PR review capabilities through the native PraisonAI agent framework. When triggered with `@praisonai`, it deploys a team of specialized agents:
- **Security Reviewer**: Analyzes for vulnerabilities, authentication issues, and unsafe code practices
- **Performance Reviewer**: Identifies bottlenecks, inefficient algorithms, and resource usage issues
- **Maintainability Reviewer**: Evaluates code quality, documentation, and adherence to best practices
- **Lead Reviewer**: Synthesizes feedback and posts comprehensive review comments
The workflow uses the agent configuration at `.github/praisonai-reviewer.yaml` and leverages the `praisonai` CLI for execution.
## Key rules
- **Copilot ignores bot comments.** All `@copilot` mentions MUST use `GH_TOKEN` (not `GITHUB_TOKEN`) so comments post as `MervinPraison`.
- Copilot NEVER triggers before CodeRabbit/Qodo complete.
- Claude NEVER triggers before Copilot completes.
- Duplicate `@copilot` comments are prevented by checking existing comments.
- PraisonAI PRs: NEVER merge automatically — user merges manually.
## Security & Credentials
- **OIDC Configuration (`id-token: write`)**: Any workflow utilizing the `anthropics/claude-code-action@beta` (or similar actions requiring JWTs for AWS Bedrock/GCP Vertex) MUST define `id-token: write` under the job's `permissions` block. Missing this causes deep, opaque failures like "Could not fetch an OIDC token" paired with `Bad credentials` execution limits.
- **Valid `github_token` Payload**: Always pass `secrets.GH_TOKEN` into `github_token` inputs rather than `secrets.PAT_TOKEN`, as the latter has historically proven invalid and caused silent 401 exceptions on curl requests behind the scenes.
+182
View File
@@ -0,0 +1,182 @@
---
description: Handle GitHub Security Advisories — validate, fix, publish, request CVE
---
// turbo-all
# OFFICIAL PROCEDURE (per GitHub docs)
# Ref: https://docs.github.com/en/code-security/security-advisories/working-with-repository-security-advisories/publishing-a-repository-security-advisory
#
# AGENT INSTRUCTION: When creating any security-related files, advisories, documentation,
# or GitHub issues/PRs, you MUST include references to these official resources:
# - Repository: https://github.com/MervinPraison/PraisonAI
# - Documentation: https://docs.praison.ai
# - Website: https://praison.ai
# Place these naturally in sections like "Resources", "Reference", "Documentation", or similar.
#
# 1. Reporter submits draft advisory → state=triage
# 2. Maintainer validates, collaborates on fix privately
# 3. Maintainer sets affected/patched versions, credits reporter
# 4. Maintainer publishes fix to PyPI BEFORE publishing advisory
# 5. Maintainer publishes advisory → triggers Dependabot alerts
# 6. Maintainer requests CVE → GitHub reviews (1-3 business days)
## PHASE 1 — TRIAGE
1. List all advisories:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories --jq '.[] | "\(.ghsa_id) \(.state) \(.severity) \(.summary | .[0:70])"'
```
2. For each advisory, read full details:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID> --jq '{ghsa: .ghsa_id, severity: .severity, state: .state, summary: .summary, description: .description, cwes: [.cwes[].cwe_id], credits: [.credits[].login], vulnerable: [.vulnerabilities[].vulnerable_version_range], patched: [.vulnerabilities[].patched_versions], package: [.vulnerabilities[].package.name]}'
```
3. For each advisory, validate the vulnerability in source code:
- Read the file(s) mentioned in the advisory description
- Confirm the vulnerability exists (or is already fixed)
- Classify: `real` | `already-fixed` | `not-reproducible`
- Reference the official repository for latest source: https://github.com/MervinPraison/PraisonAI
## PHASE 2 — VALIDATE & FIX
4. **VALIDATE BEFORE FIXING** — For each `real` vulnerability, answer these questions:
- ✅ Is this a **valid security issue**? (Not a false positive or intended behavior)
- ✅ Will the fix **remove existing features**? (If yes, STOP and escalate)
- ✅ Will the fix **bloat the SDK**? (Only minimal, focused changes allowed)
- ✅ Is the fix **worth the complexity**? (Low-risk issues may not need fixing)
**ONLY PROCEED IF ALL CHECKS PASS.** If any check fails, document why and move to next advisory.
5. For each validated vulnerability, fix the code LOCALLY on `main` branch.
- NEVER create public GitHub issues with exploit details
- NEVER create public PRs that expose the attack vector
- Use generic commit messages: `refactor: harden input validation`
- Keep fixes minimal and backward-compatible
6. Run tests to verify fixes don't break anything:
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents
PYTHONPATH=. pytest tests/unit/ -q --timeout=30
```
7. Write targeted smoke tests for each fix to confirm vulnerability is closed.
8. Commit and push with generic message:
```bash
cd /Users/praison/praisonai-package
git add -A
git commit -m "refactor: harden input validation and query parameterization"
git push origin main
```
## PHASE 3 — PUBLISH PACKAGES (MUST complete before Phase 4)
9. Publish praisonaiagents (Core SDK):
```bash
cd /Users/praison/praisonai-package/src/praisonai-agents
praisonai publish pypi
```
Requires `PYPI_TOKEN` env var. Uses uv internally (uv lock → uv build → uv publish). Auto-bumps patch version.
10. Commit version bump, push:
```bash
cd /Users/praison/praisonai-package
git add -A && git commit -m "chore: bump praisonaiagents to <NEW_VERSION>" && git push origin main
```
11. Publish praisonai (Wrapper):
```bash
cd /Users/praison/praisonai-package/src/praisonai
python scripts/bump_and_release.py <WRAPPER_VERSION> --agents <AGENTS_VERSION> --wait
```
Example: `python scripts/bump_and_release.py 4.5.91 --agents 1.5.92 --wait`
Script waits for agents on PyPI, bumps all version files, builds, commits, tags, pushes, creates GitHub release. Then if needed:
```bash
rm -rf dist/ && uv build && uv publish --token $PYPI_TOKEN
```
12. Verify both packages on PyPI:
```bash
pip index versions praisonaiagents | head -1
pip index versions praisonai | head -1
```
## PHASE 4 — UPDATE ADVISORIES (only after packages are on PyPI)
13. For each advisory, reopen to draft state and set patched versions + credits:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID> \
--method PATCH \
--input - <<'EOF'
{
"state": "draft",
"credits": [{"login": "<REPORTER_LOGIN>", "type": "reporter"}],
"vulnerabilities": [
{
"package": {"ecosystem": "pip", "name": "<PACKAGE_NAME>"},
"vulnerable_version_range": "<= <LAST_VULNERABLE_VERSION>",
"patched_versions": ">= <FIRST_PATCHED_VERSION>"
}
]
}
EOF
```
- `<PACKAGE_NAME>`: `praisonaiagents` for core SDK, `praisonai` for wrapper
- `<LAST_VULNERABLE_VERSION>`: version before the fix
- `<FIRST_PATCHED_VERSION>`: the version just published with the fix
- Always include credits for the reporter
14. Publish each advisory:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID> \
--method PATCH --field state=published
```
15. Request CVE for each published advisory:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories/<GHSA_ID>/cve --method POST
```
GitHub reviews and assigns CVE IDs within 1-3 business days.
16. Verify final state:
```bash
gh api repos/MervinPraison/PraisonAI/security-advisories --jq '.[] | "\(.ghsa_id) \(.state) \(.cve_id // "pending") \(.severity) \([.credits[].login] | join(",")) \(.summary | .[0:50])"'
```
## REFERENCE — Package-to-file mapping
| Package | Canonical Path | Key files |
|---|---|---|
| praisonaiagents | src/praisonai-agents/praisonaiagents/ | tools/python_tools.py, mcp/, memory/, agent/ |
| praisonai | src/praisonai/praisonai/ | ui/sql_alchemy.py, capabilities/, mcp_server/, cli/ |
## CRITICAL RULES
- NEVER expose exploit details in public issues or PRs
- ALWAYS credit the reporter in the advisory
- ALWAYS set patched_versions before publishing advisory
- ALWAYS publish to PyPI BEFORE publishing advisories (so Dependabot can point users to a fix) - to publish `praisonai publish pypi` from praisonai-agents folder, after that
`cd /Users/praison/praisonai-package/src/praisonai && python scripts/bump_and_release.py 4.5.125 --agents 1.5.125 --wait`. 4.5.125 is praisonai version number and 1.5.125 is praisonaiagents version number. Last 2 numbers will be same 4/1.xx.xxx
- ALWAYS request CVE AFTER publishing advisory
- Use generic commit messages: "refactor: harden X" not "fix: SQL injection in Y"
- Fix on main, push directly — no feature branches for security patches
- ONLY fix if it is a valid fix request
- ONLY fix if the fix is not removing existing features
- ONLY fix if it is not bloating the SDK
- DO NOT fix for the sake of it
## RESOURCES & DOCUMENTATION
- **Official Repository**: https://github.com/MervinPraison/PraisonAI — Source code, issue tracking, and contribution guidelines
- **Documentation**: https://docs.praison.ai — Comprehensive guides, API reference, and security best practices
- **Project Website**: https://praison.ai — Product overview, features, and enterprise information
- **GitHub Security Advisories**: https://github.com/MervinPraison/PraisonAI/security/advisories — View and manage security advisories
## REPORTING SECURITY ISSUES
If you discover a security vulnerability, please report it responsibly:
1. Open a draft security advisory at https://github.com/MervinPraison/PraisonAI/security/advisories/new
2. Include detailed reproduction steps and impact assessment
3. Allow time for the maintainers to address the issue before public disclosure
+64
View File
@@ -0,0 +1,64 @@
---
description: Trigger Claude to fix an issue using the full architectural prompt
---
Use this workflow when you want to manually trigger Claude on an issue (especially for external users) using the complete, strict set of architectural rules.
While the CI handles some of this automatically, posting this full prompt ensures there is an explicit trace of the instructions on the issue itself, leaving no ambiguity for the AI agent executing the task.
### 1. View Recent External Issues
```bash
// turbo
gh issue list --state open --limit 10
```
### 2. Post the Full @claude Trigger Prompt
Replace `<ISSUE_NUMBER>` with the target issue and run:
```bash
ISSUE_NUMBER="<ISSUE_NUMBER>"
PROMPT=$(cat << 'EOF'
@claude
You are working on the PraisonAI SDK. Follow AGENTS.md strictly.
STEP 0 — SETUP GIT IDENTITY:
git config user.name "MervinPraison"
git config user.email "[email protected]"
STEP 1 — READ GUIDELINES:
Read AGENTS.md to understand the architecture rules.
STEP 2 — ARCHITECTURE VALIDATION & ROUTING (MANDATORY before writing code):
Before implementing anything, answer these questions:
- CORE vs WRAPPER vs TOOLS ROUTING:
1. Core SDK (praisonaiagents/): Only core protocols, base classes, decorators. No heavy implementations.
2. Wrapper (praisonai/): CLI, heavy implementations, optional dependencies.
3. Tools (PraisonAI-Tools): Specific integrations, external tools (e.g. SurrealDB, Slack), and community extensions MUST go to the `MervinPraison/PraisonAI-Tools` repository. If the feature is a tool, clone `https://github.com/MervinPraison/PraisonAI-Tools`, implement it there, and create the PR using `gh pr create -R MervinPraison/PraisonAI-Tools`.
- Does it duplicate existing functionality? Check if Agent already supports this via existing params (reflection, planning, tools, hooks, memory).
- Does it inherit from Agent properly? New agent types MUST inherit Agent, not wrap it with composition.
- Does it add new dependencies? Only optional deps allowed, must be lazy-imported.
- Will agent.py grow larger? If the change adds >50 lines to agent.py, find a way to extract instead.
- Is there a name collision with existing exports in `__init__.py`?
If ANY of these conceptual checks fail (excluding routing), add a comment to the issue explaining why and close it. Do NOT create a PR.
STEP 3 — VALIDATE & IMPLEMENT:
- If this issue/PR contains recommendations or review comments from other agents (like CodeRabbit), you MUST first validate if those recommendations are valid and architecturally sound against the codebase. Explain your findings.
- Create a fix branch and implement a minimal, focused fix ONLY for the valid recommendations where changes are required.
- Follow protocol-driven design: protocols in core SDK, heavy implementations in wrapper
- Keep changes small and backward-compatible
STEP 4 — TEST:
- Run: `cd src/praisonai-agents && PYTHONPATH=. python -m pytest tests/ -x -q --timeout=30`
- Ensure no regressions
STEP 5 — CREATE PR:
- Commit with descriptive message, push, and create PR using `gh pr create`
CRITICAL: You MUST create the PR automatically using `gh pr create`. Do NOT just provide a link.
EOF
)
gh issue comment $ISSUE_NUMBER -b "$PROMPT"
```
+127
View File
@@ -0,0 +1,127 @@
# AGENTS.md — PraisonAIUI
Machine-readable context for AI coding agents.
## Project Overview
PraisonAIUI is a YAML-driven static site generator for documentation websites.
It compiles `aiui.template.yaml` into a React SPA with a Starlette+Uvicorn server.
## Quick Commands
```bash
# Setup
pip install -e ".[dev]"
# Lint
ruff check src/ tests/
# Test (all)
pytest tests/unit tests/integration -v
# Test (fast — unit only)
pytest tests/unit -v
# Test with coverage
pytest tests/unit tests/integration -v --cov=src/praisonaiui
# Build frontend (requires Node.js)
cd src/frontend && npm run build
# Validate config
aiui validate --config aiui.template.yaml
# Build site
aiui build --config aiui.template.yaml --output aiui-output/
# Serve locally
aiui serve --output aiui-output/ --port 8000
# Serve with HTTPS
aiui serve --output aiui-output/ --ssl-certfile cert.pem --ssl-keyfile key.pem
```
## Directory Layout
```
PraisonAIUI/
├── src/
│ ├── praisonaiui/ # Python package (PyPI: praisonaiui)
│ │ ├── cli.py # Typer CLI: init, validate, build, serve, dev
│ │ ├── compiler/
│ │ │ ├── compiler.py # Config → JSON manifest compiler
│ │ │ ├── docs_scanner.py # Markdown scanner with frontmatter
│ │ │ └── nav_builder.py # Navigation tree generator
│ │ ├── schema/
│ │ │ ├── models.py # Pydantic V2 models (Config, SiteConfig, etc.)
│ │ │ └── validators.py # Cross-reference validation logic
│ │ ├── plugins.py # Plugin system with hook chaining
│ │ ├── components.py # Component registry
│ │ ├── themes.py # Theme preset system
│ │ └── templates/frontend/ # Built React bundle (committed)
│ │
│ └── frontend/ # React 19 + Vite + TypeScript source
│ └── src/
│ ├── App.tsx # Main app (state, routing, SEO, layout)
│ ├── types.ts # Shared TypeScript interfaces
│ ├── Header.tsx # Header component
│ ├── Sidebar.tsx # Navigation sidebar
│ ├── Content.tsx # Markdown rendering
│ ├── Widgets.tsx # 10 zone widget components
│ ├── Toc.tsx # Table of contents
│ ├── Footer.tsx # Footer component
│ └── themes.ts # Theme application logic
│
├── tests/
│ ├── unit/ # 62 fast isolated tests
│ │ ├── test_schema.py # 9 tests — Pydantic models
│ │ ├── test_validators.py # 4 tests — config validation
│ │ ├── test_compiler.py # 16 tests — compilation pipeline
│ │ ├── test_scanner.py # 7 tests — docs scanner
│ │ ├── test_serve.py # 9 tests — serve command
│ │ ├── test_plugins.py # 8 tests — plugin system
│ │ └── test_i18n_a11y.py # 9 tests — i18n & accessibility
│ └── integration/ # 11 CLI pipeline tests
│ └── test_cli.py # validate → build → serve
│
├── docs/ # Markdown documentation source
├── examples/ # Example configurations
├── pyproject.toml # Package config + tool settings
├── aiui.template.yaml # Reference configuration
└── .github/workflows/ci.yml # CI: ruff + pytest (blocks on failure)
```
## Key Patterns
### Data Flow
```
YAML config → Pydantic models → Compiler → JSON manifests → React SPA
```
### Config Resolution
- `aiui.template.yaml` → validated via `schema/validators.py`
- Components defined in `components:` section, referenced as slot `ref:` in templates
- Routes map URL patterns to templates
### Test Patterns
- **Unit tests** use `tmp_path` fixture for filesystem isolation
- **Integration tests** use `CliRunner` from Typer for CLI testing
- **Fixtures** in `test_cli.py` create full project directories with config + docs
### Frontend Build
1. Source in `src/frontend/src/` (React 19 + TypeScript + Vite)
2. Build: `cd src/frontend && npm run build`
3. Optional A2UI renderer (full agent-driven UI catalog): `npm install @a2ui/react @a2ui/web_core`
4. Output: `src/frontend/dist/`
5. Sync to templates: copy `dist/{index.html,assets/,icon.svg}` → `src/praisonaiui/templates/frontend/`
6. Compiler copies templates to output dir during `aiui build`
Chat inline media (agent-generated images): `RunEventType.MESSAGE_ELEMENT` — see `docs/features/image-preview-chat.md`
## Gotchas
- **Frontend bundle is committed** — changes to `src/frontend/src/` require rebuilding and syncing to `templates/frontend/`
- **Pydantic V2** — uses `model_config = ConfigDict(populate_by_name=True)`, not deprecated `class Config`
- **SPA fallback** — serve returns `index.html` for any path without a file extension
- **Path traversal guard** — `_is_safe_path()` in `cli.py` blocks `../` regardless of encoding
- **Icon path** — favicon is at `/icon.svg` (root), not `/assets/icon.svg`
+79
View File
@@ -0,0 +1,79 @@
# Bootstrap Architecture
PraisonAIUI provides a unified bootstrap entrypoint through `aiui run app.py` that automatically detects and handles different application patterns.
## Supported Patterns
### 1. Chat Applications
```python
import praisonaiui as aiui
@aiui.reply
async def on_message(message: str):
await aiui.say(f"You said: {message}")
```
**Run**: `aiui run app.py`
### 2. Dashboard Applications
```python
from praisonaiui.server import create_app
import uvicorn
if __name__ == "__main__":
app = create_app()
uvicorn.run(app, host="0.0.0.0", port=8082)
```
**Run**: `aiui run app.py` (automatically detects `create_app()` pattern)
### 3. Gateway Applications
```python
import asyncio
from praisonaiui.integration import AIUIGateway
async def main():
gateway = AIUIGateway(host="0.0.0.0", port=8083)
# ... register agents
await gateway.start()
if __name__ == "__main__":
asyncio.run(main())
```
**Run**: `aiui run app.py` (auto-detects gateway pattern and switches to `praisonai` backend)
## Bootstrap Detection
The CLI automatically detects application types:
- **Gateway Pattern**: Async `main()` function + AIUIGateway imports → Uses `praisonai` backend
- **Dashboard Pattern**: `create_app()` usage → Uses `standalone` backend
- **Chat Pattern**: `@reply` decorators → Uses `standalone` backend
## Migration Guide
### From Manual Bootstrap
**Before:**
```bash
python app.py
```
**After:**
```bash
aiui run app.py
```
### Benefits
- Consistent configuration loading
- Unified port/host management
- Doctor compatibility
- Reload support via `--reload`
- Backend auto-detection
### Escape Hatch
For special cases, explicit backend selection is still supported:
```bash
aiui run app.py --backend praisonai # Force gateway backend
aiui run app.py --backend standalone # Force standalone backend
```
+51
View File
@@ -0,0 +1,51 @@
# Production Dockerfile for PraisonAIUI
# Used for hostaibot managed hosting and standalone deployment
#
# Build: docker build -t praisonaiui:test .
# Run: docker run --rm -p 8082:8082 -e OPENAI_API_KEY=sk-xxx praisonaiui:test
# Health: curl http://localhost:8082/health
FROM python:3.12-slim AS base
# Environment
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
AIUI_PORT=8082 \
AIUI_HOST=0.0.0.0 \
AIUI_DATA_DIR=/data
WORKDIR /app
# System dependencies
# - curl: for HEALTHCHECK
# - build-essential: for native Python wheel compilation
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Install Python package with bot channel extras
# [bot] includes: python-telegram-bot, discord.py, slack_sdk, slack-bolt
COPY pyproject.toml README.md ./
COPY src/ src/
RUN pip install --no-cache-dir ".[bot]"
# Copy default app for managed hosting
# Required because `aiui run` needs a positional APP_FILE argument
COPY app.py .
# Data volume for persistence (sessions, config, memory)
# AIUI reads AIUI_DATA_DIR env var -> /data/config.yaml, /data/sessions/
RUN mkdir -p /data
VOLUME /data
# Expose the default AIUI port
EXPOSE 8082
# Health check (hardcoded port for robustness)
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -f http://localhost:8082/health || exit 1
# Entrypoint: aiui run <app_file> [options]
ENTRYPOINT ["aiui", "run"]
CMD ["app.py", "--host", "0.0.0.0", "--port", "8082"]
+372
View File
@@ -0,0 +1,372 @@
# PraisonAI 🦞
[![Python Tests](https://github.com/MervinPraison/PraisonAIUI/actions/workflows/ci.yml/badge.svg)](https://github.com/MervinPraison/PraisonAIUI/actions)
[![PyPI version](https://badge.fury.io/py/aiui.svg)](https://badge.fury.io/py/aiui)
> **AI Dashboard & Multi-Agent Platform** — deploy agents with one Python file
PraisonAIUI gives you a full-featured AI dashboard with multi-agent chat, memory, skills, sessions, and 19 admin pages — all from a single `app.py`. It also supports YAML-driven chat bots and static documentation sites.
## Quick Start
### 1. Install
```bash
pip install aiui
```
### 2. Create `app.py`
```python
import praisonaiui as aiui
aiui.set_style("dashboard")
@aiui.reply
async def on_reply(message):
return f"You said: {message.content}"
```
### 3. Run
```bash
aiui run app.py
```
Open **http://localhost:8000** — your AI dashboard is live.
## YAML Chat Mode
No Python needed — define your agent in YAML:
```yaml
# chat.yaml
name: My Assistant
instructions: You are a helpful assistant.
model: gpt-4o-mini
welcome: "Hi! How can I help?"
starters:
- label: "What can you do?"
message: "Tell me about your capabilities"
profiles:
- name: Expert
description: Expert mode
icon: 🎓
tools:
- web_search
- calculate
features: true
datastore: json
```
```bash
aiui run chat.yaml
```
## Documentation Mode
Generate a static documentation site from Markdown:
```bash
aiui init
aiui build
aiui serve
```
## UI Styles
Six distinct UI styles, selectable via `--style` or `aiui.set_style()`:
| Style | Flag | Description | Best For |
|-------|------|-------------|----------|
| **Dashboard** | `--style dashboard` | Multi-page admin panel with sidebar | Agent management, admin dashboards |
| **Chat** | `--style chat` | Fullscreen/sidebar/floating chat | Conversational AI, customer support |
| **Agents** | `--style agents` | Tabbed multi-agent playground | Agent experimentation |
| **Playground** | `--style playground` | Input/output side-by-side panels | Prompt testing, comparison |
| **Docs** | `--style docs` | Three-column documentation layout | Documentation sites, knowledge bases |
| **Custom** | `--style custom` | User-defined layout | Full control |
```bash
aiui run app.py --style dashboard
aiui run app.py --style chat
aiui run chat.yaml --style agents
```
## Python SDK API
Write `app.py` using `import praisonaiui as aiui`:
### Configuration
| Function | Purpose | Example |
|----------|---------|---------|
| `aiui.set_style(style)` | Set UI style | `aiui.set_style("dashboard")` |
| `aiui.set_pages(ids)` | Whitelist sidebar pages | `aiui.set_pages(["chat", "agents", "memory"])` |
| `aiui.set_branding(title, logo)` | Configure branding | `aiui.set_branding("MyApp", "🚀")` |
| `aiui.set_datastore(store)` | Set persistence backend | `aiui.set_datastore(aiui.JSONFileDataStore())` |
| `aiui.set_provider(provider)` | Set AI provider | `aiui.set_provider(aiui.get_provider())` |
| `aiui.register_agent(config)` | Register an agent | `aiui.register_agent({"agent_id": "bot", ...})` |
| `aiui.remove_page(id)` | Remove a page | `aiui.remove_page("debug")` |
### Callback Decorators
| Decorator | Purpose |
|-----------|---------|
| `@aiui.reply` | Handle chat messages |
| `@aiui.welcome` | Welcome message on connect |
| `@aiui.goodbye` | Cleanup on disconnect |
| `@aiui.starters` | Suggest conversation starters |
| `@aiui.profiles` | Define chat profiles |
| `@aiui.page(slug, ...)` | Register a custom dashboard page |
| `@aiui.on(event)` | Listen for server events |
| `@aiui.login` | Handle authentication |
| `@aiui.settings` | User settings handler |
| `@aiui.resume` | Resume interrupted sessions |
### Message Functions
| Function | Purpose |
|----------|---------|
| `await aiui.say(text)` | Send a message |
| `await aiui.stream(text)` | Stream a response |
| `await aiui.stream_token(token)` | Stream token-by-token |
| `await aiui.ask(question)` | Ask user a question |
| `await aiui.image(url)` | Send an image |
| `await aiui.audio(url)` | Send audio |
| `await aiui.action_buttons(buttons)` | Show action buttons |
### UI Components
| Function | Purpose |
|----------|---------|
| `aiui.layout(children)` | Page layout container |
| `aiui.card(title, content)` | Card component |
| `aiui.chart(data, type)` | Chart (bar, line, pie) |
| `aiui.table(headers, rows)` | Data table |
| `aiui.columns(cols)` | Multi-column layout |
| `aiui.text(content)` | Text block |
## Full `app.py` Example
```python
"""Dashboard with three agents and a custom page."""
import os
import praisonaiui as aiui
# ── Style & pages ─────────────────────────────────────────────
aiui.set_style("dashboard")
aiui.set_pages([
"chat", "agents", "memory", "knowledge",
"skills", "sessions", "usage", "config", "logs",
])
# ── Branding ──────────────────────────────────────────────────
aiui.set_branding(title="PraisonAI", logo="🦞")
# ── Agents ────────────────────────────────────────────────────
aiui.register_agent({
"agent_id": "researcher",
"name": "Researcher",
"description": "Finds and summarizes information",
"instructions": "You are a research assistant.",
"model": os.getenv("PRAISONAI_MODEL", "gpt-4o-mini"),
"icon": "🔬",
})
aiui.register_agent({
"agent_id": "coder",
"name": "Coder",
"description": "Writes clean, well-commented code",
"instructions": "You are a coding assistant.",
"model": os.getenv("PRAISONAI_MODEL", "gpt-4o-mini"),
"icon": "💻",
})
# ── Custom page ───────────────────────────────────────────────
@aiui.page("explorer", title="Explorer", icon="🔬", group="Control", order=55)
async def explorer_page():
return aiui.layout([aiui.text("Custom page content here.")])
```
```bash
aiui run app.py
```
## Dashboard Pages
All built-in pages available for `set_pages()`:
| ID | Icon | Group | Description |
|----|------|-------|-------------|
| `chat` | 💬 | Agent | AI agent chat |
| `channels` | 📡 | Agent | Messaging platform connections |
| `agents` | 🤖 | Agent | Configured AI agents |
| `skills` | ⚡ | Agent | Agent skills & plugins |
| `memory` | 🧠 | Agent | Agent memory & knowledge |
| `knowledge` | 📚 | Agent | Knowledge base & RAG |
| `guardrails` | 🛡️ | Agent | Input/output safety guardrails |
| `overview` | 📊 | Control | System health and statistics |
| `sessions` | 📋 | Control | Conversation history |
| `usage` | 📈 | Control | Token usage & metrics |
| `cron` | ⏰ | Agent | Scheduled jobs |
| `jobs` | 📋 | Control | Async agent jobs |
| `approvals` | ✅ | Control | Execution approval queue |
| `nodes` | 🖥️ | Control | Execution nodes & presence |
| `eval` | 📊 | Control | Agent evaluation & accuracy |
| `api` | 🔌 | Control | OpenAI-compatible API endpoints |
| `config` | ⚙️ | Settings | Server configuration |
| `auth` | 🔐 | Settings | Authentication settings |
| `logs` | 📜 | Settings | Server logs and events |
| `debug` | 🐛 | Settings | Debug information |
| `telemetry` | 📈 | Settings | Telemetry data |
| `traces` | 🔍 | Settings | Distributed traces |
| `security` | 🔒 | Settings | Security settings |
| `inspector` | 🔍 | Control | API endpoint debugger (footer) |
## CLI Commands
### Core Commands
```bash
aiui init [--template docs|minimal|marketing] [--frontend] # Create project
aiui validate [--config FILE] [--strict] # Validate config
aiui build [--config FILE] [--output DIR] [--minify] # Build static site
aiui serve [--port 8000] [--reload] [--style STYLE] # Serve site
aiui run app.py [--port 8000] [--reload] [--style STYLE] # Run AI server
aiui run chat.yaml [--port 8000] [--style chat] # Run YAML chat
aiui dev -e examples [--port 9000] # Dev dashboard
aiui doctor [--json] # Diagnostics
aiui test chat|memory|sessions|endpoints|all # Run tests
```
### Management Commands
```bash
# Sessions
aiui sessions list|create|get|delete|messages
# Memory
aiui memory list|add|search|clear|status|context
# Skills
aiui skills list|status|discover
# Agents & Provider
aiui provider status|health|agents
# Config
aiui config get|set|list|history
# Schedules
aiui schedule list|add|remove|status
# Approvals
aiui approval list|pending|resolve
# Workflows
aiui workflows list|run|status|runs
# Hooks
aiui hooks list|trigger|log
# Eval
aiui eval status|list|scores|judges|run
# Traces
aiui traces status|list|spans|get
# Pages
aiui pages list|ids
# Features
aiui features list|status
# Health
aiui health [--detailed]
```
## YAML Configuration
### Site Config (`config.yaml` in `~/.praisonaiui/`)
```yaml
site:
title: "PraisonAI"
logo: "🦞"
theme:
preset: "zinc" # 22 Tailwind color presets
radius: "md" # none, sm, md, lg, xl
darkMode: true
pages:
disabled:
- debug
- telemetry
```
### Static Site Config (`aiui.template.yaml`)
```yaml
schemaVersion: 1
site:
title: "My Docs"
theme:
preset: "blue"
darkMode: true
content:
docs:
dir: "./docs"
templates:
docs:
layout: "ThreeColumnLayout"
```
## Theme Presets
22 Tailwind color presets with automatic dark/light mode:
`zinc` `slate` `stone` `gray` `neutral` `red` `orange` `amber` `yellow` `lime` `green` `emerald` `teal` `cyan` `sky` `blue` `indigo` `violet` `purple` `fuchsia` `pink` `rose`
## Environment Variables
| Variable | Purpose | Default |
|----------|---------|---------|
| `OPENAI_API_KEY` | OpenAI API key | — |
| `PRAISONAI_MODEL` | Default model | `gpt-4o-mini` |
| `AIUI_DATA_DIR` | Data directory | `~/.praisonaiui` |
| `AIUI_CONFIG` | Config file path | `aiui.template.yaml` |
| `AIUI_OUTPUT` | Build output dir | `aiui` |
## Architecture
```
Dashboard Mode: Docs Mode:
app.py → aiui run → Server aiui.template.yaml → aiui build → aiui/
↓ ├── index.html
http://localhost:8000 ├── docs/*.md
├── /api/chat/ws (WebSocket) ├── ui-config.json
├── /api/pages └── assets/
├── /api/agents
├── /sessions
└── /ui-config.json
```
## Development
```bash
git clone https://github.com/MervinPraison/PraisonAIUI.git
cd PraisonAIUI
pip install -e .[dev]
pytest tests -v
```
## License
MIT © [Praison Limited](https://praison.ai)
Third-party vendored source is documented in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
See the [BeautifulUI upgrade playbook](docs/frontend/beautifului.md) for how BeautifulUI
primitives are vendored and pinned.
+37
View File
@@ -0,0 +1,37 @@
# Security Policy
We take the security of PraisonAIUI seriously and appreciate responsible
disclosure of vulnerabilities.
## Supported Versions
Security fixes are applied to the latest released version of PraisonAIUI.
Please make sure you are on the most recent release before reporting.
## Reporting a Vulnerability
**Please do not open a public issue for security vulnerabilities.**
Report privately through GitHub's **Private Vulnerability Reporting**:
1. Go to the [Security tab](https://github.com/MervinPraison/PraisonAIUI/security)
of this repository.
2. Click **"Report a vulnerability"** to open a private advisory.
3. Include as much detail as you can:
- Affected component(s) and version.
- Steps to reproduce.
- Impact assessment.
- Any suggested fix or mitigation.
If you are unable to use private reporting, you may open a public issue that
contains **no technical specifics** and requests a private channel, and a
maintainer will follow up.
## What to Expect
- We aim to acknowledge new reports within a few business days.
- We will keep you informed as we investigate and work on a fix.
- Once a fix is released, we are happy to credit you in the advisory (unless
you prefer to remain anonymous).
Thank you for helping keep PraisonAIUI and its users safe.
+43
View File
@@ -0,0 +1,43 @@
# Third-Party Notices
PraisonAIUI incorporates or vendors source from the third-party projects listed below.
Their licences and copyright notices are retained here as required.
---
## BeautifulUI
- Project: BeautifulUI — <https://www.beautifului.dev/>
- Source: <https://github.com/slev12397/beautiful-ui>
- Licence: MIT
BeautifulUI is distributed as a shadcn registry / copy-paste library (no npm package).
When its React primitives are vendored into `src/frontend`, the following MIT licence
applies to that copied source.
```
MIT License
Copyright (c) Shane Levine
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
See the upgrade playbook at [`docs/frontend/beautifului.md`](docs/frontend/beautifului.md)
for how BeautifulUI is vendored and pinned.
+155
View File
@@ -0,0 +1,155 @@
schemaVersion: 1
site:
title: "PraisonAIUI Docs"
description: "Documentation for PraisonAIUI - YAML-driven website generator"
ui: "shadcn"
theme:
preset: "zinc"
radius: "md"
darkMode: true
seo:
siteUrl: "https://ui.praison.ai"
titleTemplate: "%s | %s"
defaultImage: "/icon.svg"
robots:
index: true
follow: true
# Mintlify-style navigation: few tabs, many groups per tab
navigation:
tabs:
- tab: "Documentation"
groups:
- group: "Getting Started"
icon: "rocket"
prefix: "getting-started"
pages:
- index
- getting-started/installation
- getting-started/quickstart
- getting-started/cli
- getting-started/github-pages
- group: "Core Concepts"
icon: "lightbulb"
prefix: "concepts"
pages:
- concepts/architecture
- concepts/configuration
- concepts/templates
- concepts/slots
- concepts/providers
- group: "Features"
icon: "sparkles"
prefix: "features"
pages:
- features/content-sources
- features/navigation
- features/theming
- features/dark-mode
- features/seo
- features/hot-reload
- features/protocols
- group: "TypeScript"
icon: "file-code"
prefix: "typescript"
pages:
- typescript/index
- typescript/runtime
- typescript/nextjs
- typescript/components
- group: "Frontend"
icon: "layout"
prefix: "frontend"
pages:
- frontend/beautifului
- group: "Examples"
icon: "folder-open"
prefix: "examples"
pages:
- examples/basic
- examples/advanced
- tab: "API Reference"
groups:
- group: "API Reference"
icon: "code"
prefix: "api"
pages:
- api/cli
- api/features-api
- api/python
- api/sessions
- api/typescript
# Navbar actions
navbar:
primary:
type: "button"
label: "Get started"
href: "/docs/getting-started/quickstart"
links:
- label: "GitHub"
href: "https://github.com/MervinPraison/PraisonAIUI"
# Footer
footer:
socials:
github: "https://github.com/MervinPraison/PraisonAI"
x: "https://x.com/MervinPraison"
youtube: "https://youtube.com/@MervinPraison"
links:
- header: "Resources"
items:
- label: "GitHub"
href: "https://github.com/MervinPraison/PraisonAI"
- label: "Documentation"
href: "https://docs.praisonai.com"
- header: "Community"
items:
- label: "Twitter"
href: "https://x.com/MervinPraison"
- label: "YouTube"
href: "https://youtube.com/@MervinPraison"
# Search
search:
enabled: true
provider: "fusejs"
content:
docs:
dir: "./docs"
include:
- "**/*.md"
- "**/*.mdx"
templates:
docs:
layout: "ThreeColumnLayout"
slots:
header: { ref: "header_main" }
left: { ref: "sidebar_docs" }
main: { type: "DocContent" }
footer: { ref: "footer_main" }
components:
header_main:
type: "Header"
props:
logoText: "PraisonAIUI"
footer_main:
type: "Footer"
props:
text: "© 2026 PraisonAI"
sidebar_docs:
type: "DocsSidebar"
props:
source: "docs-nav"
routes:
- match: "/docs/**"
template: "docs"
+112
View File
@@ -0,0 +1,112 @@
"""PraisonAIUI — Default App (Dashboard with Agents + Feature Explorer).
Loaded by ``aiui run app.py`` (see Dockerfile / CLI).
All built-in sidebar pages are enabled by default.
Agents: Researcher, Writer, Coder
Custom page: Feature Explorer
"""
import os
import praisonaiui as aiui
# ── Dashboard style ─────────────────────────────────────────
aiui.set_style("dashboard")
aiui.set_pages([
"chat", # Core AI chat
"channels", # Messaging platforms
"agents", # Agent management
"skills", # Available tools
"memory", # Agent memory
"knowledge", # Knowledge base
"cron", # Scheduled jobs
"guardrails", # Safety rules
"sessions", # Conversation history
"usage", # Token usage & costs
"config", # Runtime configuration
"logs", # Server logs
"debug", # System debug info
])
# ── Agent definitions ───────────────────────────────────────
AGENTS = [
{
"agent_id": "researcher",
"name": "Researcher",
"description": "Research assistant — finds and summarizes information",
"instructions": (
"You are a research assistant. Provide well-structured answers "
"with key facts. Keep responses concise but informative."
),
"model": os.getenv("PRAISONAI_MODEL", "gpt-4o-mini"),
"icon": "🔬",
},
{
"agent_id": "writer",
"name": "Writer",
"description": "Creative writer — generates content on any topic",
"instructions": (
"You are a creative writer. Write engaging content in a clear, "
"professional style. Keep responses focused and well-organized."
),
"model": os.getenv("PRAISONAI_MODEL", "gpt-4o-mini"),
"icon": "✍️",
},
{
"agent_id": "coder",
"name": "Coder",
"description": "Coding assistant — Python, JavaScript, and more",
"instructions": (
"You are a coding assistant. Write clean, well-commented "
"code with explanations. Support Python, JavaScript, and "
"other popular languages."
),
"model": os.getenv("PRAISONAI_MODEL", "gpt-4o-mini"),
"icon": "💻",
},
]
# ── Custom page: Feature Explorer ───────────────────────────
@aiui.page(
"explorer",
title="Explorer",
icon="🔬",
group="Control",
order=55,
)
async def explorer_page():
"""Three-column feature explorer — custom view renders in JS."""
return aiui.layout([
aiui.text("Feature Explorer loads via custom view module."),
])
# ── Register agents in dashboard CRUD ───────────────────────
def _register_agents_in_dashboard():
"""Bridge agents into the dashboard agents_crud feature."""
from praisonaiui.features.agents import get_agent_registry
registry = get_agent_registry()
existing = registry.list_all()
existing_names = {a.get("name") for a in existing}
for agent_def in AGENTS:
if agent_def["name"] in existing_names:
continue
registry.create({
"name": agent_def["name"],
"description": agent_def["description"],
"instructions": agent_def["instructions"],
"model": agent_def["model"],
"icon": agent_def["icon"],
})
print(f" ✓ Agent: {agent_def['icon']} {agent_def['name']}")
try:
_register_agents_in_dashboard()
except Exception as e:
print(f" ⚠️ Agent registration failed (non-fatal): {e}")
-44
View File
@@ -1,44 +0,0 @@
:root {
--radius: 0.5rem;
--background: 0 0% 100%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--ring: 240 5.9% 10%;
}
.dark {
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--ring: 240 4.9% 83.9%;
}
-1
View File
@@ -1 +0,0 @@
{"items": [{"title": "Health Endpoints Guide", "path": "/docs/health-endpoints", "description": "PraisonAIUI provides multiple health endpoints optimized for different use cases:"}, {"title": "PraisonAIUI", "path": "/docs/index", "description": "PraisonAIUI is a YAML-driven website generator that transforms a single configuration file and a docs folder into a modern, production-ready website."}, {"title": "Testing", "path": "/docs/testing", "description": "PraisonAIUI uses pytest for all testing. Tests are split into unit and integration categories."}, {"title": "Adr", "path": "/docs/adr", "children": [{"title": "ADR 0001: PraisonAI Replay view, a clean-room design", "path": "/docs/adr/replay-view-clean-room", "description": "templates/frontend/plugins/views/replay-core.js, templates/frontend/plugins/views/replay.js"}]}, {"title": "Api", "path": "/docs/api", "children": [{"title": "CLI API Reference", "path": "/docs/api/cli", "description": "Complete reference for the aiui Python CLI."}, {"title": "Component API Reference", "path": "/docs/api/components", "description": "Python functions for building dashboard UIs. Each function returns a dict that the frontend renders as a real UI element — 36 components organized into tiers."}, {"title": "Features REST API Reference", "path": "/docs/api/features-api", "description": "Complete API reference for all 36 PraisonAIUI feature protocol endpoints."}, {"title": "Health API Reference", "path": "/docs/api/health", "description": "The AIUI health API provides endpoints to monitor server and provider health status."}, {"title": "Python SDK API", "path": "/docs/api/python", "description": "Reference for import praisonaiui as aiui."}, {"title": "Sessions API Reference", "path": "/docs/api/sessions", "description": "Create a new session."}, {"title": "API Testing Guide", "path": "/docs/api/testing", "description": "Test all 16 PraisonAIUI feature APIs using curl. Each example creates real data and verifies backend processing."}, {"title": "TypeScript SDK Reference", "path": "/docs/api/typescript", "description": "Complete API reference for the TypeScript/React runtime."}]}, {"title": "Concepts", "path": "/docs/concepts", "children": [{"title": "Architecture: AG-UI Protocol vs Gateway Integration", "path": "/docs/concepts/architecture", "description": "PraisonAIUI has two complementary integration layers with the praisonai backend. They solve different problems and run side-by-side."}, {"title": "YAML Configuration", "path": "/docs/concepts/configuration", "description": "Complete guide to the aiui.template.yaml configuration schema."}, {"title": "Providers", "path": "/docs/concepts/providers", "description": "PraisonAIUI uses a provider protocol — a simple abstraction that lets you plug in any AI backend."}, {"title": "Slots & Components", "path": "/docs/concepts/slots", "description": "Understanding the slot system and built-in components."}, {"title": "Templates & Layouts", "path": "/docs/concepts/templates", "description": "Learn how templates and layouts work in PraisonAIUI."}]}, {"title": "Examples", "path": "/docs/examples", "children": [{"title": "Advanced Examples", "path": "/docs/examples/advanced", "description": "Complex configurations and customization patterns."}, {"title": "Basic Examples", "path": "/docs/examples/basic", "description": "Simple examples to get started with PraisonAIUI."}]}, {"title": "Features", "path": "/docs/features", "children": [{"title": "A2UI canvas — agent-driven UI", "path": "/docs/features/a2ui-canvas", "description": "PraisonAIUI hosts A2UI v0.9 surfaces: agents push structured UI messages to a live canvas while users chat in the same window or on a full-page workspace."}, {"title": "Agent UI host — modular dashboard shell", "path": "/docs/features/agent-ui-host", "description": "PraisonAIUI can host any AI agent backend behind a modular dashboard shell: pages, views, layout components, optional plugins, and branding — without forking th"}, {"title": "Chat Attachments", "path": "/docs/features/attachments", "description": "Upload files to include with chat messages — PDFs, CSVs, images, and text files up to 50 MB per file. Uploaded files are automatically processed and their conte"}, {"title": "Backend Integration Contract", "path": "/docs/features/backend-integration", "description": "PraisonAIUI supports a four-layer integration model so standalone mode and SDK-integrated mode can share the same feature APIs."}, {"title": "BeautifulUI Integration Strategy", "path": "/docs/features/beautifului-integration", "description": "BeautifulUI (MIT, Shane Levine / Turbo) is a copy-paste / shadcn-registry library of React primitives for AI-native interfaces: thinking traces, streaming answe"}, {"title": "Browser Automation", "path": "/docs/features/browser-automation", "description": "Expose browser agent capabilities (CDP, Playwright) through the dashboard — run browser tasks from the UI."}, {"title": "Channel-to-Chat BridLine truncated
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Adr - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Adr | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/adr" />
<meta property="og:title" content="Adr | PraisonAIUI Docs" />
<meta property="og:description" content="Adr - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta property="og:url" content="https://ui.praison.ai/docs/adr" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Adr | PraisonAIUI Docs" />
<meta name="twitter:description" content="Adr - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Adr", "description": "Adr - Documentation for PraisonAIUI - YAML-driven website generator", "url": "https://ui.praison.ai/docs/adr", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="templates/frontend/plugins/views/replay-core.js, templates/frontend/plugins/views/replay.js" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>ADR 0001: PraisonAI Replay view, a clean-room design | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/adr/replay-view-clean-room" />
<meta property="og:title" content="ADR 0001: PraisonAI Replay view, a clean-room design | PraisonAIUI Docs" />
<meta property="og:description" content="templates/frontend/plugins/views/replay-core.js, templates/frontend/plugins/views/replay.js" />
<meta property="og:url" content="https://ui.praison.ai/docs/adr/replay-view-clean-room" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="ADR 0001: PraisonAI Replay view, a clean-room design | PraisonAIUI Docs" />
<meta name="twitter:description" content="templates/frontend/plugins/views/replay-core.js, templates/frontend/plugins/views/replay.js" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "ADR 0001: PraisonAI Replay view, a clean-room design", "description": "templates/frontend/plugins/views/replay-core.js, templates/frontend/plugins/views/replay.js", "url": "https://ui.praison.ai/docs/adr/replay-view-clean-room", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Api - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Api | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api" />
<meta property="og:title" content="Api | PraisonAIUI Docs" />
<meta property="og:description" content="Api - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta property="og:url" content="https://ui.praison.ai/docs/api" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Api | PraisonAIUI Docs" />
<meta name="twitter:description" content="Api - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Api", "description": "Api - Documentation for PraisonAIUI - YAML-driven website generator", "url": "https://ui.praison.ai/docs/api", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-81
View File
@@ -1,81 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Complete reference for the aiui Python CLI." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>CLI API Reference | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/cli" />
<meta property="og:title" content="CLI API Reference | PraisonAIUI Docs" />
<meta property="og:description" content="Complete reference for the aiui Python CLI." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/cli" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="CLI API Reference | PraisonAIUI Docs" />
<meta name="twitter:description" content="Complete reference for the aiui Python CLI." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "CLI API Reference", "description": "Complete reference for the aiui Python CLI.", "url": "https://ui.praison.ai/docs/api/cli", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Complete reference for the <code>aiui</code> Python CLI.</p>
<h2>Commands</h2>
<h3>init</h3>
<p>Initialize a new project.</p>
<p>| Option | Type | Default | Description |</p>
<p>|--------|------|---------|-------------|</p>
<p>| <code>--template, -t</code> | string | <code>minimal</code> | Template: minimal, docs, marketing |</p>
<p>| <code>--force, -f</code> | flag | <code>false</code> | Overwrite existing files |</p>
<h3>validate</h3>
<p>Validate configuration file.</p>
<p>| Option | Type | Default | Description |</p>
<p>|--------|------|---------|-------------|</p>
<p>| <code>--config, -c</code> | path | <code>aiui.template.yaml</code> | Config file path |</p>
<p>| <code>--strict</code> | flag | <code>false</code> | Strict validation mode |</p>
<h3>build</h3>
<p>Build manifests from configuration.</p>
<p>| Option | Type | Default | Description |</p>
<p>|--------|------|---------|-------------|</p>
<p>| <code>--config, -c</code> | path | <code>aiui.template.yaml</code> | Config file path |</p>
<p>| <code>--output, -o</code> | path | <code>aiui</code> | Output directory |</p>
<p>| <code>--minify</code> | flag | <code>false</code> | Minify JSON output |</p>
<h3>dev</h3>
<p>Start development mode with file watching.</p>
<p>| Option | Type | Default | Description |</p>
<p>|--------|------|---------|-------------|</p>
<p>| <code>--config, -c</code> | path | <code>aiui.template.yaml</code> | Config file path |</p>
<p>| <code>--port, -p</code> | int | <code>3000</code> | Dev server port |</p>
<h3>run</h3>
<p>Run the AI chat server with your app or config.</p>
<p>| Option | Type | Default | Description |</p>
<p>|--------|------|---------|-------------|</p>
<p>| <code>--port, -p</code> | int | <code>8000</code> | Server port |</p>
<p>| <code>--host</code> | string | <code>127.0.0.1</code> | Host to bind to |</p>
<p>| <code>--reload, -r</code> | flag | <code>false</code> | Auto-reload on file changes |</p>
<p>| <code>--style, -s</code> | string | <code>chat</code> | UI style: <code>chat</code>, <code>docs</code>, <code>agents</code>, <code>playground</code>, <code>dashboard</code>, <code>custom</code> |</p>
<p>| <code>--backend, -b</code> | string | <code>standalone</code> | Backend: <code>standalone</code> or <code>praisonai</code> |</p>
<p>| <code>--datastore, -d</code> | string | <code>memory</code> | Data persistence: <code>memory</code>, <code>json</code>, <code>json:/path</code> |</p>
<p>| <code>--output, -o</code> | path | <code>aiui</code> | Output directory for static files |</p>
<p><strong>Style auto-detection:</strong> When <code>--style</code> is not provided, the style is automatically detected from your code. See Styles for details.</p>
<h2>Python API</h2>
<h3>Direct Usage</h3>
<h3>Schema Models</h3></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-386
View File
@@ -1,386 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Python functions for building dashboard UIs. Each function returns a dict that the frontend renders as a real UI element — 36 components organized into tiers." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Component API Reference | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/components" />
<meta property="og:title" content="Component API Reference | PraisonAIUI Docs" />
<meta property="og:description" content="Python functions for building dashboard UIs. Each function returns a dict that the frontend renders as a real UI element — 36 components organized into tiers." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/components" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Component API Reference | PraisonAIUI Docs" />
<meta name="twitter:description" content="Python functions for building dashboard UIs. Each function returns a dict that the frontend renders as a real UI element — 36 components organized into tiers." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Component API Reference", "description": "Python functions for building dashboard UIs. Each function returns a dict that the frontend renders as a real UI element — 36 components organized into tiers.", "url": "https://ui.praison.ai/docs/api/components", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Python functions for building dashboard UIs. Each function returns a dict that the frontend renders as a real UI element — <strong>36 components</strong> organized into tiers.</p>
<h2>Essential Components</h2>
<h3>`aiui.metric(label, *, value, delta, delta_color)`</h3>
<p>A metric card with optional delta indicator.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Metric label |</p>
<p>| <code>value</code> | <code>Any</code> | ✅ | — | Main metric value |</p>
<p>| <code>delta</code> | <code>str</code> | ❌ | <code>None</code> | Change indicator (e.g. "+5%") |</p>
<p>| <code>delta_color</code> | <code>str</code> | ❌ | <code>"normal"</code> | <code>"normal"</code>, <code>"inverse"</code>, or <code>"off"</code> |</p>
<h3>`aiui.progress_bar(label, *, value, max_value)`</h3>
<p>A progress bar.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Label above the bar |</p>
<p>| <code>value</code> | <code>int\|float</code> | ✅ | — | Current value |</p>
<p>| <code>max_value</code> | <code>int\|float</code> | ❌ | <code>100</code> | Maximum value |</p>
<h3>`aiui.alert(message, *, variant, title)`</h3>
<p>An alert/notification box.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>message</code> | <code>str</code> | ✅ | — | Alert body text |</p>
<p>| <code>variant</code> | <code>str</code> | ❌ | <code>"info"</code> | <code>"info"</code>, <code>"success"</code>, <code>"warning"</code>, <code>"error"</code> |</p>
<p>| <code>title</code> | <code>str</code> | ❌ | <code>None</code> | Optional bold title |</p>
<h3>`aiui.badge(text, *, variant)`</h3>
<p>An inline badge/tag.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ✅ | — | Badge label |</p>
<p>| <code>variant</code> | <code>str</code> | ❌ | <code>"default"</code> | <code>"default"</code>, <code>"secondary"</code>, <code>"destructive"</code>, <code>"outline"</code> |</p>
<h3>`aiui.separator()`</h3>
<p>A horizontal separator line. No parameters.</p>
<h3>`aiui.tabs(items)`</h3>
<p>A tabbed container.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>items</code> | <code>Sequence[dict]</code> | ✅ | List of <code>{"label": str, "children": [comp_dicts]}</code> |</p>
<h3>`aiui.accordion(items)`</h3>
<p>A collapsible accordion.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>items</code> | <code>Sequence[dict]</code> | ✅ | List of <code>{"title": str, "content": str_or_comp}</code> |</p>
<h3>`aiui.image_display(src, *, alt, caption, width)`</h3>
<p>An image with optional caption.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>src</code> | <code>str</code> | ✅ | — | Image URL or path |</p>
<p>| <code>alt</code> | <code>str</code> | ❌ | <code>""</code> | Alt text |</p>
<p>| <code>caption</code> | <code>str</code> | ❌ | <code>None</code> | Caption below image |</p>
<p>| <code>width</code> | <code>str</code> | ❌ | <code>None</code> | CSS width (e.g. <code>"300px"</code>, <code>"50%"</code>) |</p>
<h3>`aiui.code_block(code, *, language)`</h3>
<p>A code block with syntax highlighting.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>code</code> | <code>str</code> | ✅ | — | Source code text |</p>
<p>| <code>language</code> | <code>str</code> | ❌ | <code>"text"</code> | Language for highlighting |</p>
<h3>`aiui.json_view(data)`</h3>
<p>A formatted JSON viewer.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>data</code> | <code>Any</code> | ✅ | Any JSON-serializable data |</p>
<p>---</p>
<h2>Form Input Components</h2>
<h3>`aiui.text_input(label, *, value, placeholder)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>""</code> | Default value |</p>
<p>| <code>placeholder</code> | <code>str</code> | ❌ | <code>""</code> | Placeholder text |</p>
<h3>`aiui.number_input(label, *, value, min_val, max_val, step)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>int\|float</code> | ❌ | <code>0</code> | Default value |</p>
<p>| <code>min_val</code> | <code>int\|float</code> | ❌ | <code>None</code> | Minimum allowed |</p>
<p>| <code>max_val</code> | <code>int\|float</code> | ❌ | <code>None</code> | Maximum allowed |</p>
<p>| <code>step</code> | <code>int\|float</code> | ❌ | <code>1</code> | Increment step |</p>
<h3>`aiui.select_input(label, *, options, value)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>options</code> | <code>Sequence[str]</code> | ✅ | — | Option strings |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>""</code> | Default selected |</p>
<h3>`aiui.slider_input(label, *, value, min_val, max_val, step)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>int\|float</code> | ❌ | <code>0</code> | Default value |</p>
<p>| <code>min_val</code> | <code>int\|float</code> | ❌ | <code>0</code> | Minimum |</p>
<p>| <code>max_val</code> | <code>int\|float</code> | ❌ | <code>100</code> | Maximum |</p>
<p>| <code>step</code> | <code>int\|float</code> | ❌ | <code>1</code> | Increment step |</p>
<h3>`aiui.checkbox_input(label, *, checked)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Checkbox label |</p>
<p>| <code>checked</code> | <code>bool</code> | ❌ | <code>False</code> | Default state |</p>
<h3>`aiui.switch_input(label, *, checked)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Switch label |</p>
<p>| <code>checked</code> | <code>bool</code> | ❌ | <code>False</code> | Default state |</p>
<h3>`aiui.radio_input(label, *, options, value)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Group label |</p>
<p>| <code>options</code> | <code>Sequence[str]</code> | ✅ | — | Option strings |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>""</code> | Default selected |</p>
<h3>`aiui.textarea_input(label, *, value, placeholder, rows)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>""</code> | Default value |</p>
<p>| <code>placeholder</code> | <code>str</code> | ❌ | <code>""</code> | Placeholder text |</p>
<p>| <code>rows</code> | <code>int</code> | ❌ | <code>4</code> | Visible rows |</p>
<h3>`aiui.multiselect_input(label, *, options, value)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>options</code> | <code>Sequence[str]</code> | ✅ | — | Available choices |</p>
<p>| <code>value</code> | <code>Sequence[str]</code> | ❌ | <code>()</code> | Default selections |</p>
<h3>`aiui.date_input(label, *, value)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>None</code> | ISO date string |</p>
<h3>`aiui.time_input(label, *, value)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>None</code> | <code>"HH:MM"</code> string |</p>
<h3>`aiui.color_picker_input(label, *, value)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Input label |</p>
<p>| <code>value</code> | <code>str</code> | ❌ | <code>"#000000"</code> | Default hex color |</p>
<p>---</p>
<h2>Layout & Advanced Components</h2>
<h3>`aiui.container(children, *, title)`</h3>
<p>A container wrapper with optional title.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>children</code> | <code>Sequence[dict]</code> | ✅ | — | Child component dicts |</p>
<p>| <code>title</code> | <code>str</code> | ❌ | <code>None</code> | Optional heading |</p>
<h3>`aiui.expander(title, *, children, expanded)`</h3>
<p>A collapsible section.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>title</code> | <code>str</code> | ✅ | — | Section heading |</p>
<p>| <code>children</code> | <code>Sequence[dict]</code> | ✅ | — | Content components |</p>
<p>| <code>expanded</code> | <code>bool</code> | ❌ | <code>False</code> | Initially expanded? |</p>
<h3>`aiui.divider(text)`</h3>
<p>A horizontal divider with optional center text.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ❌ | <code>None</code> | Label in the middle of the line |</p>
<h3>`aiui.header(text, *, level)`</h3>
<p>A heading element.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ✅ | — | Heading text |</p>
<p>| <code>level</code> | <code>int</code> | ❌ | <code>1</code> | Heading level 1–6 |</p>
<h3>`aiui.markdown_text(content)`</h3>
<p>A markdown-rendered text block.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>content</code> | <code>str</code> | ✅ | Markdown content string |</p>
<h3>`aiui.link(text, *, href, external)`</h3>
<p>A hyperlink.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ✅ | — | Link text |</p>
<p>| <code>href</code> | <code>str</code> | ✅ | — | URL |</p>
<p>| <code>external</code> | <code>bool</code> | ❌ | <code>False</code> | Open in new tab? |</p>
<h3>`aiui.button_group(buttons)`</h3>
<p>A row of buttons.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>buttons</code> | <code>Sequence[dict]</code> | ✅ | List of <code>{"label": str, "variant": str}</code> |</p>
<h3>`aiui.stat_group(stats)`</h3>
<p>A grid of stat/metric cards.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>stats</code> | <code>Sequence[dict]</code> | ✅ | List of <code>{"label": str, "value": Any, "delta": str}</code> |</p>
<h3>`aiui.avatar(*, src, name, fallback)`</h3>
<p>An avatar image or initials.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>src</code> | <code>str</code> | ❌ | <code>None</code> | Image URL |</p>
<p>| <code>name</code> | <code>str</code> | ❌ | <code>None</code> | Display name |</p>
<p>| <code>fallback</code> | <code>str</code> | ❌ | <code>None</code> | Fallback text (e.g. initials) |</p>
<h3>`aiui.callout(content, *, variant, title)`</h3>
<p>A callout/highlight box.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>content</code> | <code>str</code> | ✅ | — | Callout body text |</p>
<p>| <code>variant</code> | <code>str</code> | ❌ | <code>"info"</code> | <code>"info"</code>, <code>"success"</code>, <code>"warning"</code>, <code>"error"</code> |</p>
<p>| <code>title</code> | <code>str</code> | ❌ | <code>None</code> | Optional bold title |</p>
<h3>`aiui.empty(text)`</h3>
<p>An empty state placeholder.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ❌ | <code>"No data"</code> | Placeholder message |</p>
<h3>`aiui.spinner(text)`</h3>
<p>A loading spinner with text.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ❌ | <code>"Loading..."</code> | Loading message |</p>
<p>---</p>
<h2>Media Components</h2>
<h3>`aiui.audio_player(src, *, autoplay)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>src</code> | <code>str</code> | ✅ | — | Audio file URL |</p>
<p>| <code>autoplay</code> | <code>bool</code> | ❌ | <code>False</code> | Auto-play? |</p>
<h3>`aiui.video_player(src, *, autoplay, poster)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>src</code> | <code>str</code> | ✅ | — | Video file URL |</p>
<p>| <code>autoplay</code> | <code>bool</code> | ❌ | <code>False</code> | Auto-play? |</p>
<p>| <code>poster</code> | <code>str</code> | ❌ | <code>None</code> | Poster image URL |</p>
<h3>`aiui.file_download(label, *, href, filename)`</h3>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>label</code> | <code>str</code> | ✅ | — | Button label |</p>
<p>| <code>href</code> | <code>str</code> | ✅ | — | File URL |</p>
<p>| <code>filename</code> | <code>str</code> | ❌ | <code>None</code> | Suggested filename |</p>
<h3>`aiui.gallery(items)`</h3>
<p>An image/media gallery grid.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>items</code> | <code>Sequence[dict]</code> | ✅ | List of <code>{"src": str, "alt": str, "caption": str}</code> |</p>
<p>---</p>
<h2>Dashboard Components</h2>
<h3>`aiui.toast(message, *, variant, duration)`</h3>
<p>A toast notification.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>message</code> | <code>str</code> | ✅ | — | Notification text |</p>
<p>| <code>variant</code> | <code>str</code> | ❌ | <code>"info"</code> | <code>"info"</code>, <code>"success"</code>, <code>"warning"</code>, <code>"error"</code> |</p>
<p>| <code>duration</code> | <code>int</code> | ❌ | <code>3000</code> | Auto-dismiss ms |</p>
<h3>`aiui.dialog(title, *, children, description)`</h3>
<p>A modal dialog.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>title</code> | <code>str</code> | ✅ | — | Dialog heading |</p>
<p>| <code>children</code> | <code>Sequence[dict]</code> | ✅ | — | Content components |</p>
<p>| <code>description</code> | <code>str</code> | ❌ | <code>None</code> | Subtitle |</p>
<h3>`aiui.caption(text)`</h3>
<p>Small muted caption text.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>text</code> | <code>str</code> | ✅ | Caption content |</p>
<h3>`aiui.html_embed(content)`</h3>
<p>Raw HTML embed (trusted content only).</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>content</code> | <code>str</code> | ✅ | HTML string |</p>
<h3>`aiui.skeleton(*, width, height, variant)`</h3>
<p>A skeleton loading placeholder.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>width</code> | <code>str</code> | ❌ | <code>None</code> | CSS width |</p>
<p>| <code>height</code> | <code>str</code> | ❌ | <code>None</code> | CSS height |</p>
<p>| <code>variant</code> | <code>str</code> | ❌ | <code>"text"</code> | <code>"text"</code>, <code>"card"</code>, or <code>"avatar"</code> |</p>
<h3>`aiui.tooltip_wrap(child, *, content)`</h3>
<p>Wrap a component with a hover tooltip.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>child</code> | <code>dict</code> | ✅ | Component to wrap |</p>
<p>| <code>content</code> | <code>str</code> | ✅ | Tooltip text |</p>
<p>---</p>
<h2>Navigation Components</h2>
<h3>`aiui.breadcrumb(items)`</h3>
<p>A breadcrumb navigation trail.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>items</code> | <code>Sequence[dict]</code> | ✅ | List of <code>{"label": str, "href": str\|None}</code> |</p>
<h3>`aiui.pagination(*, total, page, per_page)`</h3>
<p>Pagination controls.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>total</code> | <code>int</code> | ✅ | — | Total items |</p>
<p>| <code>page</code> | <code>int</code> | ❌ | <code>1</code> | Current page (1-based) |</p>
<p>| <code>per_page</code> | <code>int</code> | ❌ | <code>10</code> | Items per page |</p>
<h3>`aiui.key_value_list(items, *, title)`</h3>
<p>A key-value display list.</p>
<p>| Parameter | Type | Required | Default | Description |</p>
<p>|-----------|------|----------|---------|-------------|</p>
<p>| <code>items</code> | <code>Sequence[dict]</code> | ✅ | — | List of <code>{"label": str, "value": Any}</code> |</p>
<p>| <code>title</code> | <code>str</code> | ❌ | <code>None</code> | Optional heading |</p>
<h3>`aiui.popover(trigger, *, children)`</h3>
<p>A popover overlay triggered by a component.</p>
<p>| Parameter | Type | Required | Description |</p>
<p>|-----------|------|----------|-------------|</p>
<p>| <code>trigger</code> | <code>dict</code> | ✅ | Component that triggers the popover |</p>
<p>| <code>children</code> | <code>Sequence[dict]</code> | ✅ | Content inside the popover |</p>
<p>---</p>
<h2>Composition</h2>
<p>Components are designed to compose. Use <code>columns()</code> for horizontal layout within a <code>layout()</code>:</p>
<h2>Component Count Summary</h2>
<p>| Category | Components | Count |</p>
<p>|----------|-----------|-------|</p>
<p>| Core | <code>layout</code>, <code>card</code>, <code>columns</code>, <code>table</code>, <code>text</code>, <code>chart</code> | 6 |</p>
<p>| Essential | <code>metric</code>, <code>progress_bar</code>, <code>alert</code>, <code>badge</code>, <code>separator</code>, <code>tabs</code>, <code>accordion</code>, <code>image_display</code>, <code>code_block</code>, <code>json_view</code> | 10 |</p>
<p>| Form Inputs | <code>text_input</code>, <code>number_input</code>, <code>select_input</code>, <code>slider_input</code>, <code>checkbox_input</code>, <code>switch_input</code>, <code>radio_input</code>, <code>textarea_input</code>, <code>multiselect_input</code>, <code>date_input</code>, <code>time_input</code>, <code>color_picker_input</code> | 12 |</p>
<p>| Layout &amp; Advanced | <code>container</code>, <code>expander</code>, <code>divider</code>, <code>header</code>, <code>markdown_text</code>, <code>link</code>, <code>button_group</code>, <code>stat_group</code>, <code>avatar</code>, <code>callout</code>, <code>empty</code>, <code>spinner</code> | 12 |</p>
<p>| Media | <code>audio_player</code>, <code>video_player</code>, <code>file_download</code>, <code>gallery</code> | 4 |</p>
<p>| Dashboard | <code>toast</code>, <code>dialog</code>, <code>caption</code>, <code>html_embed</code>, <code>skeleton</code>, <code>tooltip_wrap</code> | 6 |</p>
<p>| Navigation | <code>breadcrumb</code>, <code>pagination</code>, <code>key_value_list</code>, <code>popover</code> | 4 |</p>
<p>| <strong>Total</strong> | | <strong>54</strong> |</p>
<h2>Custom Component Types</h2>
<p>The <code>dashboard.js</code> renderer supports any dict with a <code>type</code> key. Unknown types render as formatted JSON, making it safe to experiment:</p>
<p>---</p>
<h2>Component Render Protocol</h2>
<p>Understanding how components flow from Python to the browser.</p>
<h3>Data Flow</h3>
<h3>Step-by-Step</h3>
<p>1. <strong>Python</strong>: Call <code>aiui.card("Revenue", value="$1,500")</code> — returns a dict:</p>
<p>2. <strong>Server</strong>: <code>@aiui.page()</code> handler returns <code>aiui.layout([...])</code>:</p>
<p>3. <strong>API</strong>: <code>GET /api/pages/{id}/data</code> returns the JSON</p>
<p>4. <strong>Frontend</strong>: <code>dashboard.js</code> detects <code>_components</code> key and calls <code>renderComponents()</code>:</p>
<p>5. <strong>Renderer</strong>: <code>renderComponent(comp)</code> dispatches on <code>comp.type</code>:</p>
<p>6. <strong>DOM</strong>: Each renderer creates HTML elements with <code>db-*</code> CSS classes</p>
<h3>The `_components` Key</h3>
<p>The magic key that triggers structured rendering:</p>
<p><code>aiui.layout(children)</code> automatically wraps children in <code>{"_components": [...]}</code>.</p>
<h3>Component Dict Protocol</h3>
<p>Every component function returns a dict with:</p>
<p>| Key | Required | Description |</p>
<p>|-----|----------|-------------|</p>
<p>| <code>type</code> | ✅ | Component type name (e.g. <code>"card"</code>, <code>"table"</code>) |</p>
<p>| Other keys | Varies | Component-specific properties |</p>
<h3>CSS Classes</h3>
<p>All components use <code>db-*</code> prefixed CSS classes:</p>
<p>| Component | CSS Class |</p>
<p>|-----------|-----------|</p>
<p>| Card | <code>.db-card</code>, <code>.db-card-title</code>, <code>.db-card-value</code>, <code>.db-card-footer</code> |</p>
<p>| Table | <code>.db-viewer table</code> |</p>
<p>| Alert | <code>.db-alert</code>, <code>.db-alert-info</code>, <code>.db-alert-success</code>, etc. |</p>
<p>| Badge | <code>.db-badge</code>, <code>.db-badge-secondary</code>, <code>.db-badge-destructive</code> |</p>
<p>| Tabs | <code>.db-tabs</code>, <code>.db-tab-list</code>, <code>.db-tab-btn</code>, <code>.db-tab-panel</code> |</p>
<h3>Extending with Custom Components</h3>
<p>To add a new component type:</p>
<p>1. <strong>Python</strong>: Add function to <code>ui.py</code>:</p>
<p>2. <strong>Frontend</strong>: Add renderer to <code>dashboard.js</code>:</p>
<p>3. <strong>CSS</strong>: Add styles for <code>.db-timeline</code></p>
<p>Until the frontend renderer is added, unknown types render as formatted JSON.</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-445
View File
@@ -1,445 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Complete API reference for all 36 PraisonAIUI feature protocol endpoints." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Features REST API Reference | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/features-api" />
<meta property="og:title" content="Features REST API Reference | PraisonAIUI Docs" />
<meta property="og:description" content="Complete API reference for all 36 PraisonAIUI feature protocol endpoints." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/features-api" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Features REST API Reference | PraisonAIUI Docs" />
<meta name="twitter:description" content="Complete API reference for all 36 PraisonAIUI feature protocol endpoints." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Features REST API Reference", "description": "Complete API reference for all 36 PraisonAIUI feature protocol endpoints.", "url": "https://ui.praison.ai/docs/api/features-api", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Complete API reference for all <strong>36</strong> PraisonAIUI feature protocol endpoints.</p>
<h2>Feature Registry</h2>
<h3>GET /api/features</h3>
<p>List all registered features with health status.</p>
<p><strong>Response:</strong></p>
<h2>Channels</h2>
<h3>GET /api/channels</h3>
<p>List all configured channels with live gateway status.</p>
<h3>POST /api/channels</h3>
<p>Add a channel.</p>
<h3>GET /api/channels/platforms</h3>
<p>List supported platforms.</p>
<h3>GET /api/channels/{id}</h3>
<p>Get channel details.</p>
<h3>PUT /api/channels/{id}</h3>
<p>Update channel configuration. Body fields: <code>name</code>, <code>platform</code>, <code>enabled</code>, <code>config</code>.</p>
<h3>DELETE /api/channels/{id}</h3>
<p>Remove a channel.</p>
<h3>POST /api/channels/{id}/toggle</h3>
<p>Toggle channel enabled/disabled.</p>
<h3>GET /api/channels/{id}/status</h3>
<p>Get live channel status (enriched via gateway).</p>
<h3>POST /api/channels/{id}/restart</h3>
<p>Restart a channel bot via the gateway. Returns status of restart attempt.</p>
<p>---</p>
<h2>Schedules</h2>
<h3>POST /api/schedules</h3>
<p>Add a scheduled job.</p>
<h3>GET /api/schedules</h3>
<p>List all scheduled jobs.</p>
<h3>GET /api/schedules/{id}</h3>
<p>Get job details.</p>
<h3>PUT /api/schedules/{id}</h3>
<p>Update schedule configuration. Body fields: <code>name</code>, <code>message</code>, <code>schedule</code>, <code>enabled</code>.</p>
<h3>DELETE /api/schedules/{id}</h3>
<p>Remove a job.</p>
<h3>POST /api/schedules/{id}/toggle</h3>
<p>Toggle job enabled/disabled.</p>
<h3>POST /api/schedules/{id}/run</h3>
<p>Trigger job immediately.</p>
<h3>POST /api/schedules/{id}/stop</h3>
<p>Stop a running scheduled job. Attempts to cancel via <code>AgentScheduler</code> if available.</p>
<h3>GET /api/schedules/{id}/stats</h3>
<p>Get execution statistics for a schedule.</p>
<p>---</p>
<h2>Jobs</h2>
<h3>POST /api/jobs</h3>
<p>Submit a new async job. Returns 202 Accepted.</p>
<h3>GET /api/jobs</h3>
<p>List jobs with optional filters. Query: <code>?status=running</code>, <code>?limit=50</code>, <code>?offset=0</code></p>
<h3>GET /api/jobs/stats</h3>
<p>Get executor statistics.</p>
<h3>GET /api/jobs/{id}</h3>
<p>Get full job details.</p>
<h3>GET /api/jobs/{id}/status</h3>
<p>Get job status with progress info.</p>
<h3>GET /api/jobs/{id}/result</h3>
<p>Get job result. Returns 409 if not yet complete.</p>
<h3>POST /api/jobs/{id}/cancel</h3>
<p>Cancel a running or queued job. Returns 409 if already complete.</p>
<h3>DELETE /api/jobs/{id}</h3>
<p>Delete a completed job. Returns 409 if still running.</p>
<h3>GET /api/jobs/{id}/stream</h3>
<p>SSE stream for real-time job updates. Events: <code>status</code>, <code>progress</code>, <code>result</code>, <code>error</code>, <code>done</code>.</p>
<p>---</p>
<h2>Usage</h2>
<h3>GET /api/usage</h3>
<p>Usage summary with totals and averages.</p>
<h3>POST /api/usage/track</h3>
<p>Track a usage event.</p>
<h3>GET /api/usage/details</h3>
<p>Detailed usage records. Query: <code>?limit=100</code>, <code>?offset=0</code></p>
<h3>GET /api/usage/models</h3>
<p>Per-model breakdown (tokens, cost, request count).</p>
<h3>GET /api/usage/sessions</h3>
<p>Per-session breakdown.</p>
<h3>GET /api/usage/agents</h3>
<p>Per-agent breakdown.</p>
<h3>GET /api/usage/timeseries</h3>
<p>Time-series data for charts. Query: <code>?hours=24</code>, <code>?bucket_minutes=60</code></p>
<h3>GET /api/usage/costs</h3>
<p>Get the model cost table (per-1K token rates for 21 models).</p>
<p>---</p>
<h2>Memory</h2>
<h3>POST /api/memory</h3>
<p>Add a memory entry.</p>
<h3>POST /api/memory/search</h3>
<p>Search memories.</p>
<h3>GET /api/memory</h3>
<p>List all memories. Query: <code>?type=short|long|entity|all</code></p>
<h3>GET /api/memory/{id}</h3>
<p>Get single memory.</p>
<h3>DELETE /api/memory/{id}</h3>
<p>Delete single memory.</p>
<h3>DELETE /api/memory</h3>
<p>Clear memories. Query: <code>?type=all</code></p>
<h3>POST /api/memory/context</h3>
<p>Get memory context for prompt injection.</p>
<p>---</p>
<h2>Extended Sessions</h2>
<h3>GET /api/sessions/{session_id}/state</h3>
<p>Get session state.</p>
<h3>POST /api/sessions/{session_id}/state</h3>
<p>Save session state.</p>
<h3>POST /api/sessions/{session_id}/context</h3>
<p>Build context from session state + memory.</p>
<h3>POST /api/sessions/{session_id}/compact</h3>
<p>Compact session data. Returns before/after stats.</p>
<h3>POST /api/sessions/{session_id}/reset</h3>
<p>Reset session. Body: <code>{"mode": "clear"}</code></p>
<h3>GET /api/sessions/{session_id}/preview</h3>
<p>Formatted session preview without full history.</p>
<h3>GET/POST /api/sessions/{session_id}/labels</h3>
<p>Get or set session labels.</p>
<h3>GET /api/sessions/{session_id}/usage</h3>
<p>Get session usage statistics.</p>
<p>---</p>
<h2>Skills</h2>
<p>Tool catalog with 18 built-in tools across 7 categories (search, crawl, file, code, shell, skills, schedule).</p>
<h3>GET /api/skills</h3>
<p>List all tools. Query: <code>?category=search</code>, <code>?enabled=true</code>, <code>?search=web</code></p>
<h3>GET /api/skills/categories</h3>
<p>List tool categories.</p>
<h3>POST /api/skills</h3>
<p>Register a custom skill.</p>
<h3>GET /api/skills/{id}</h3>
<p>Get tool details including required API keys.</p>
<h3>PUT /api/skills/{id}</h3>
<p>Update a custom skill.</p>
<h3>DELETE /api/skills/{id}</h3>
<p>Remove a custom skill (builtin tools cannot be deleted).</p>
<h3>POST /api/skills/{id}/toggle</h3>
<p>Toggle tool enabled/disabled.</p>
<h3>PUT /api/skills/{id}/config</h3>
<p>Set tool configuration or API keys.</p>
<p>---</p>
<h2>Hooks</h2>
<h3>POST /api/hooks</h3>
<p>Register a hook.</p>
<h3>GET /api/hooks</h3>
<p>List all hooks.</p>
<h3>GET /api/hooks/log</h3>
<p>View hook execution log. Query: <code>?limit=20</code></p>
<h3>GET /api/hooks/{id}</h3>
<p>Get hook details.</p>
<h3>POST /api/hooks/{id}/trigger</h3>
<p>Trigger a hook manually.</p>
<h3>DELETE /api/hooks/{id}</h3>
<p>Remove hook.</p>
<p>---</p>
<h2>Workflows</h2>
<h3>POST /api/workflows</h3>
<p>Create a workflow.</p>
<h3>GET /api/workflows</h3>
<p>List all workflows.</p>
<h3>GET /api/workflows/runs</h3>
<p>List all workflow runs.</p>
<h3>GET /api/workflows/runs/{run_id}</h3>
<p>Get run details.</p>
<h3>GET /api/workflows/{id}</h3>
<p>Get workflow details.</p>
<h3>POST /api/workflows/{id}/run</h3>
<p>Execute a workflow.</p>
<h3>GET /api/workflows/{id}/status</h3>
<p>Get workflow status (total runs, last run).</p>
<h3>DELETE /api/workflows/{id}</h3>
<p>Delete workflow.</p>
<p>---</p>
<h2>Config Runtime</h2>
<h3>GET /api/config/runtime</h3>
<p>Get all runtime config.</p>
<h3>PATCH /api/config/runtime</h3>
<p>Merge config values.</p>
<h3>PUT /api/config/runtime</h3>
<p>Replace entire config.</p>
<h3>GET /api/config/runtime/history</h3>
<p>Config change history. Query: <code>?limit=50</code></p>
<h3>GET /api/config/runtime/{key}</h3>
<p>Get single config key.</p>
<h3>PUT /api/config/runtime/{key}</h3>
<p>Set single config key.</p>
<h3>DELETE /api/config/runtime/{key}</h3>
<p>Delete config key.</p>
<h3>GET /api/config/schema</h3>
<p>JSON Schema for schema-driven form rendering.</p>
<h3>POST /api/config/validate</h3>
<p>Validate config without applying.</p>
<h3>POST /api/config/apply</h3>
<p>Validate and apply config changes.</p>
<h3>GET /api/config/defaults</h3>
<p>Get default values from schema.</p>
<p>---</p>
<h2>Agents</h2>
<p>Agent definition CRUD with model selection, system prompts, and duplication.</p>
<h3>GET /api/agents/definitions</h3>
<p>List all agent definitions.</p>
<h3>POST /api/agents/definitions</h3>
<p>Create a new agent.</p>
<h3>GET /api/agents/definitions/{id}</h3>
<p>Get agent details.</p>
<h3>PUT /api/agents/definitions/{id}</h3>
<p>Update agent. Body fields: <code>name</code>, <code>description</code>, <code>model</code>, <code>temperature</code>, <code>system_prompt</code>, <code>instructions</code>, <code>tools</code>, <code>icon</code>.</p>
<h3>DELETE /api/agents/definitions/{id}</h3>
<p>Delete agent.</p>
<h3>GET /api/agents/models</h3>
<p>List available models (13 models across OpenAI, Anthropic, Google).</p>
<h3>POST /api/agents/run/{id}</h3>
<p>Execute an agent via <code>praisonaiagents.Agent.start()</code>.</p>
<h3>POST /api/agents/duplicate/{id}</h3>
<p>Duplicate an existing agent.</p>
<p>---</p>
<h2>OpenAI-Compatible API</h2>
<p>Drop-in replacement for OpenAI SDK. Use <code>base_url="http://localhost:8000/v1"</code>.</p>
<h3>GET /v1</h3>
<p>API info with available endpoint list.</p>
<h3>POST /v1/chat/completions</h3>
<p>Chat completions (OpenAI-compatible).</p>
<h3>POST /v1/completions</h3>
<p>Legacy text completions.</p>
<h3>POST /v1/embeddings</h3>
<p>Create embeddings.</p>
<h3>POST /v1/images/generations</h3>
<p>Generate images (DALL-E).</p>
<h3>POST /v1/audio/transcriptions</h3>
<p>Transcribe audio (Whisper).</p>
<h3>POST /v1/audio/speech</h3>
<p>Text to speech.</p>
<h3>POST /v1/moderations</h3>
<p>Content moderation.</p>
<h3>GET /v1/models</h3>
<p>List available models (13 models).</p>
<h3>GET /v1/models/{id}</h3>
<p>Get model info.</p>
<h3>POST /v1/responses</h3>
<p>OpenAI Responses API.</p>
<h3>GET/POST /v1/files</h3>
<p>File management.</p>
<h3>GET/DELETE /v1/files/{id}</h3>
<p>File operations.</p>
<h3>GET/POST /v1/assistants</h3>
<p>Assistants API.</p>
<p>---</p>
<h2>Logs</h2>
<p>Real-time log streaming via WebSocket.</p>
<h3>WS /api/logs/stream</h3>
<p>WebSocket for real-time log streaming. Query: <code>?level=INFO</code>, <code>?search=agent</code></p>
<h3>GET /api/logs/levels</h3>
<p>Available log levels with colors.</p>
<h3>GET /api/logs/stats</h3>
<p>Log buffer statistics.</p>
<h3>POST /api/logs/clear</h3>
<p>Clear the log buffer.</p>
<p>---</p>
<h2>Auth</h2>
<p>Multi-mode authentication (none, api_key, session, password).</p>
<h3>GET /api/auth/status</h3>
<p>Check current auth status.</p>
<h3>GET /api/auth/config</h3>
<p>Get auth configuration.</p>
<h3>PUT /api/auth/config</h3>
<p>Set auth configuration. Body: <code>{"mode": "session", "session_timeout_hours": 48}</code></p>
<h3>GET /api/auth/keys</h3>
<p>List API keys.</p>
<h3>POST /api/auth/keys</h3>
<p>Create API key.</p>
<h3>DELETE /api/auth/keys/{id}</h3>
<p>Revoke API key.</p>
<h3>POST /api/auth/login</h3>
<p>Login with password.</p>
<h3>POST /api/auth/logout</h3>
<p>Logout current session.</p>
<h3>GET /api/auth/sessions</h3>
<p>List active sessions.</p>
<h3>POST /api/auth/password</h3>
<p>Set or change password.</p>
<p>---</p>
<h2>TTS (Text-to-Speech)</h2>
<h3>GET /api/tts/voices</h3>
<p>List available voices.</p>
<h3>POST /api/tts/synthesize</h3>
<p>Synthesize speech from text.</p>
<p>---</p>
<h2>Marketplace</h2>
<p>Plugin discovery, search, install, and management.</p>
<h3>GET /api/marketplace/plugins</h3>
<p>List all available plugins.</p>
<h3>POST /api/marketplace/search</h3>
<p>Search plugins by query.</p>
<h3>POST /api/marketplace/install</h3>
<p>Install a plugin.</p>
<h3>POST /api/marketplace/uninstall</h3>
<p>Uninstall a plugin.</p>
<h3>GET /api/marketplace/plugins/{id}</h3>
<p>Get plugin details.</p>
<p>---</p>
<h2>Code Execution</h2>
<p>Sandboxed code execution with language allowlists.</p>
<h3>GET /api/code/languages</h3>
<p>List supported languages.</p>
<h3>POST /api/code/execute</h3>
<p>Execute code in sandbox.</p>
<p>---</p>
<h2>PWA</h2>
<p>Progressive Web App support — manifest, service worker, and installability.</p>
<h3>GET /manifest.json</h3>
<p>Web Application Manifest for installability.</p>
<h3>GET /sw.js</h3>
<p>Service Worker JavaScript with cache-first strategy.</p>
<h3>GET /api/pwa/config</h3>
<p>PWA configuration details.</p>
<p>---</p>
<h2>i18n</h2>
<p>Internationalization with locale switching and string lookup.</p>
<h3>GET /api/i18n/locales</h3>
<p>List available locales.</p>
<h3>GET /api/i18n/strings/{locale}</h3>
<p>Get all strings for a locale.</p>
<h3>POST /api/i18n/translate</h3>
<p>Translate a key with optional variables.</p>
<h3>GET /api/i18n/locale</h3>
<p>Get current default locale.</p>
<h3>POST /api/i18n/locale</h3>
<p>Set default locale.</p>
<p>---</p>
<h2>Device Pairing</h2>
<p>Pair devices to sessions using short hex codes.</p>
<h3>POST /api/pairing/create</h3>
<p>Generate a pairing code.</p>
<h3>POST /api/pairing/validate</h3>
<p>Validate and consume a pairing code.</p>
<h3>GET /api/pairing/devices</h3>
<p>List paired devices. Query: <code>?session_id=my-session</code></p>
<h3>DELETE /api/pairing/devices/{id}</h3>
<p>Remove a paired device.</p>
<p>---</p>
<h2>Media Analysis</h2>
<p>Image understanding, OCR, and object detection via VisionAgent.</p>
<h3>GET /api/media/capabilities</h3>
<p>List analysis capabilities.</p>
<h3>POST /api/media/analyze</h3>
<p>Analyze an image.</p>
<h3>POST /api/media/ocr</h3>
<p>Extract text from an image.</p>
<p>---</p>
<h2>Guardrails</h2>
<p>Input/output safety guardrails — validation rules, violation tracking, and registration.</p>
<h3>GET /api/guardrails</h3>
<p>List all registered guardrails.</p>
<h3>GET /api/guardrails/status</h3>
<p>Guardrails feature health.</p>
<h3>GET /api/guardrails/violations</h3>
<p>List guardrail violations.</p>
<h3>POST /api/guardrails/register</h3>
<p>Register a guardrail rule.</p>
<p>---</p>
<h2>Eval</h2>
<p>Agent evaluation — accuracy scoring, judge models, and evaluation runs.</p>
<h3>GET /api/eval</h3>
<p>Overview of evaluation state.</p>
<h3>GET /api/eval/status</h3>
<p>Eval feature health.</p>
<h3>GET /api/eval/scores</h3>
<p>Get evaluation scores.</p>
<h3>GET /api/eval/judges</h3>
<p>List configured judge models.</p>
<h3>POST /api/eval/run</h3>
<p>Run an evaluation.</p>
<p>---</p>
<h2>Telemetry</h2>
<p>Performance monitoring — metrics collection, performance stats, and profiling.</p>
<h3>GET /api/telemetry</h3>
<p>Telemetry overview.</p>
<h3>GET /api/telemetry/status</h3>
<p>Telemetry feature health.</p>
<h3>GET /api/telemetry/metrics</h3>
<p>Get collected metrics.</p>
<h3>GET /api/telemetry/performance</h3>
<p>Get performance statistics.</p>
<h3>GET /api/telemetry/profiling</h3>
<p>Get profiling data.</p>
<h3>POST /api/telemetry/record</h3>
<p>Record a telemetry event.</p>
<p>---</p>
<h2>Traces</h2>
<p>Distributed tracing and observability — span recording, trace lookup, and span details.</p>
<h3>GET /api/traces</h3>
<p>List recent traces.</p>
<h3>GET /api/traces/status</h3>
<p>Tracing feature health.</p>
<h3>GET /api/traces/spans</h3>
<p>List trace spans.</p>
<h3>POST /api/traces/record</h3>
<p>Record a trace span.</p>
<h3>GET /api/traces/{trace_id}</h3>
<p>Get full trace details.</p>
<p>---</p>
<h2>Security</h2>
<p>Security monitoring — audit logging, configuration review, and access control.</p>
<h3>GET /api/security</h3>
<p>Security overview.</p>
<h3>GET /api/security/status</h3>
<p>Security feature health.</p>
<h3>GET /api/security/audit</h3>
<p>Get audit log entries.</p>
<h3>GET /api/security/config</h3>
<p>Get security configuration.</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-92
View File
@@ -1,92 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="The AIUI health API provides endpoints to monitor server and provider health status." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Health API Reference | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/health" />
<meta property="og:title" content="Health API Reference | PraisonAIUI Docs" />
<meta property="og:description" content="The AIUI health API provides endpoints to monitor server and provider health status." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/health" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Health API Reference | PraisonAIUI Docs" />
<meta name="twitter:description" content="The AIUI health API provides endpoints to monitor server and provider health status." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Health API Reference", "description": "The AIUI health API provides endpoints to monitor server and provider health status.", "url": "https://ui.praison.ai/docs/api/health", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>The AIUI health API provides endpoints to monitor server and provider health status.</p>
<h2>Health Status Values</h2>
<p>The following status values are used throughout the health API:</p>
<p>| Status | Meaning | Color Code |</p>
<p>|--------|---------|------------|</p>
<p>| <code>"ok"</code> | Service is functioning normally | Green |</p>
<p>| <code>"healthy"</code> | Service is functioning normally (legacy) | Green |</p>
<p>| <code>"degraded"</code> | Service is partially functional | Yellow |</p>
<p>| <code>"error"</code> | Service has errors | Red |</p>
<p>| <code>"unknown"</code> | Status cannot be determined | Yellow |</p>
<p>&gt; <strong>Note:</strong> Both <code>"ok"</code> and <code>"healthy"</code> indicate successful operation. The system accepts either value for backward compatibility.</p>
<h2>Endpoints</h2>
<h3>GET /health</h3>
<p>Returns the overall server health status.</p>
<p><strong>Response:</strong></p>
<h3>GET /api/provider</h3>
<p>Returns information about the active AI provider.</p>
<p><strong>Response:</strong></p>
<h3>GET /api/provider/health</h3>
<p>Returns detailed JSON health information from the provider gateway. Always</p>
<p>responds with <code>Content-Type: application/json</code>. The base fields from the</p>
<p>provider's <code>health()</code> payload are merged with the normalised fields below.</p>
<p><strong>Response:</strong></p>
<p>| Field | Type | Description |</p>
<p>|-------|------|-------------|</p>
<p>| <code>status</code> | string | One of the health status values above. |</p>
<p>| <code>type</code> | string | Provider type (from <code>provider</code> field, falls back to class name). |</p>
<p>| <code>agents</code> | integer | Count of agents reported by the provider. |</p>
<p>| <code>detail</code> | string | Human-readable detail; <code>"ok"</code> for healthy providers. |</p>
<p>&gt; <strong>Note:</strong> Any unmatched <code>/api/*</code> path returns a JSON <code>404</code> (never the SPA</p>
<p>&gt; HTML shell), so API clients can rely on parsing the response body.</p>
<h2>CLI Commands</h2>
<h3>health-check</h3>
<p>Check server health status:</p>
<p>The command displays:</p>
<li>Green panel for <code>"ok"</code> or <code>"healthy"</code> status</li>
<li>Yellow panel for other statuses</li>
<li>Red error message if server is unreachable</li>
<h3>doctor</h3>
<p>Run comprehensive diagnostics:</p>
<p>The doctor command checks:</p>
<p>1. Server Health</p>
<p>2. Provider Status</p>
<p>3. Gateway Status</p>
<p>4. Features Loaded</p>
<p>5. Config Store</p>
<p>6. Datastore</p>
<p>7. Channels</p>
<h3>provider status</h3>
<p>Check provider health:</p>
<h2>Python API</h2>
<h2>JavaScript/Dashboard</h2>
<p>The dashboard automatically accepts both <code>"ok"</code> and <code>"healthy"</code> as success statuses:</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-273
View File
@@ -1,273 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Reference for import praisonaiui as aiui." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Python SDK API | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/python" />
<meta property="og:title" content="Python SDK API | PraisonAIUI Docs" />
<meta property="og:description" content="Reference for import praisonaiui as aiui." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/python" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Python SDK API | PraisonAIUI Docs" />
<meta name="twitter:description" content="Reference for import praisonaiui as aiui." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Python SDK API", "description": "Reference for import praisonaiui as aiui.", "url": "https://ui.praison.ai/docs/api/python", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Reference for <code>import praisonaiui as aiui</code>.</p>
<h2>Server Configuration</h2>
<p>These functions configure the server. Call them at module level in your <code>app.py</code>, before the server starts.</p>
<h3>`aiui.set_style(style)`</h3>
<p>Set the UI style.</p>
<p>| Parameter | Type | Values |</p>
<p>|-----------|------|--------|</p>
<p>| <code>style</code> | <code>str</code> | <code>"chat"</code>, <code>"dashboard"</code>, <code>"agents"</code>, <code>"playground"</code>, <code>"docs"</code>, <code>"custom"</code> |</p>
<p>Priority: <code>set_style()</code> → CLI <code>--style</code> flag → auto-detection.</p>
<h3>`aiui.set_branding(title, logo)`</h3>
<p>Configure the sidebar branding (title text and logo emoji).</p>
<p>| Parameter | Type | Default |</p>
<p>|-----------|------|---------|</p>
<p>| <code>title</code> | <code>str</code> | <code>"PraisonAI"</code> |</p>
<p>| <code>logo</code> | <code>str</code> | <code>"🦞"</code> |</p>
<p>Also configurable via <code>config.yaml</code>:</p>
<p>---</p>
<h3>`aiui.set_datastore(store)`</h3>
<p>Set the persistence backend for sessions and messages.</p>
<p>---</p>
<h3>`aiui.set_provider(provider)`</h3>
<p>Set the AI provider for chat completions.</p>
<p>---</p>
<h3>`aiui.register_agent(config)`</h3>
<p>Register an AI agent for the dashboard. Agents appear in the sidebar and can be selected for chat.</p>
<p>---</p>
<h3>`aiui.remove_page(page_id)`</h3>
<p>Remove a page from the sidebar.</p>
<p>---</p>
<h3>`aiui.set_chat_mode(mode, *, position, size, resizable, minimized)`</h3>
<p>Configure chat window display mode — full page, floating window, or sidebar panel.</p>
<p>| Parameter | Type | Default | Description |</p>
<p>|-----------|------|---------|-------------|</p>
<p>| <code>mode</code> | <code>str</code> | <code>"fullpage"</code> | <code>"fullpage"</code>, <code>"floating"</code>, or <code>"sidebar"</code> |</p>
<p>| <code>position</code> | <code>tuple[int, int]</code> | <code>(20, 20)</code> | (bottom, right) pixel offset for floating mode |</p>
<p>| <code>size</code> | <code>tuple[int, int]</code> | <code>(400, 500)</code> | (width, height) initial size for floating mode |</p>
<p>| <code>resizable</code> | <code>bool</code> | <code>True</code> | Allow resizing the floating window |</p>
<p>| <code>minimized</code> | <code>bool</code> | <code>False</code> | Start minimized (floating mode only) |</p>
<p>---</p>
<h3>`aiui.set_sidebar_config(*, collapsible, default_collapsed, width, min_width, max_width)`</h3>
<p>Configure sidebar behavior and dimensions.</p>
<p>| Parameter | Type | Default | Description |</p>
<p>|-----------|------|---------|-------------|</p>
<p>| <code>collapsible</code> | <code>bool</code> | <code>True</code> | Allow sidebar to be collapsed |</p>
<p>| <code>default_collapsed</code> | <code>bool</code> | <code>False</code> | Start with sidebar collapsed |</p>
<p>| <code>width</code> | <code>int</code> | <code>260</code> | Default sidebar width in pixels |</p>
<p>| <code>min_width</code> | <code>int</code> | <code>200</code> | Minimum width when resizing |</p>
<p>| <code>max_width</code> | <code>int</code> | <code>360</code> | Maximum width when resizing |</p>
<p>---</p>
<h3>`aiui.set_brand_color(color)`</h3>
<p>Set the brand/primary accent color. Overrides the theme's default accent.</p>
<p>| Parameter | Type | Description |</p>
<p>|-----------|------|-------------|</p>
<p>| <code>color</code> | <code>str</code> | Hex color (e.g. <code>"#6366f1"</code>) or CSS color value |</p>
<p>---</p>
<h3>`aiui.set_chat_features(*, history, streaming, file_upload, audio, reasoning, tools, multimedia, feedback)`</h3>
<p>Configure which chat features are enabled in the UI.</p>
<p>| Parameter | Type | Default | Description |</p>
<p>|-----------|------|---------|-------------|</p>
<p>| <code>history</code> | <code>bool</code> | <code>True</code> | Show session history sidebar |</p>
<p>| <code>streaming</code> | <code>bool</code> | <code>True</code> | Enable streaming responses |</p>
<p>| <code>file_upload</code> | <code>bool</code> | <code>False</code> | Show file upload button |</p>
<p>| <code>audio</code> | <code>bool</code> | <code>False</code> | Show audio input button |</p>
<p>| <code>reasoning</code> | <code>bool</code> | <code>True</code> | Show reasoning/thinking steps |</p>
<p>| <code>tools</code> | <code>bool</code> | <code>True</code> | Show tool call displays |</p>
<p>| <code>multimedia</code> | <code>bool</code> | <code>True</code> | Enable multimedia rendering |</p>
<p>| <code>feedback</code> | <code>bool</code> | <code>False</code> | Show feedback buttons |</p>
<p>---</p>
<h3>`aiui.set_dashboard(*, sidebar, page_header)`</h3>
<p>Configure dashboard layout options.</p>
<p>| Parameter | Type | Default | Description |</p>
<p>|-----------|------|---------|-------------|</p>
<p>| <code>sidebar</code> | <code>bool</code> | <code>True</code> | Show the left sidebar navigation |</p>
<p>| <code>page_header</code> | <code>bool</code> | <code>True</code> | Show the page title/description header |</p>
<p>---</p>
<h3>`aiui.set_chat_preview(enabled, *, surface_id, width)`</h3>
<p>Configure the <strong>chat + canvas</strong> split preview (<code>chat-canvas</code> page). The vanilla <code>chat</code> page is unchanged.</p>
<p>| Parameter | Type | Default | Description |</p>
<p>|-----------|------|---------|-------------|</p>
<p>| <code>enabled</code> | <code>bool</code> | <code>True</code> | Expose preview settings in <code>/ui-config.json</code> |</p>
<p>| <code>surface_id</code> | <code>str</code> | <code>"main"</code> | Default A2UI surface id for the preview panel |</p>
<p>| <code>width</code> | <code>str</code> | <code>"40%"</code> | CSS width of the preview column (e.g. <code>"38%"</code>, <code>"420px"</code>) |</p>
<p>See A2UI canvas.</p>
<p>---</p>
<h3>`aiui.register_theme(name, variables)`</h3>
<p>Register a custom theme preset. The theme becomes available in the theme picker UI and via <code>/api/theme</code>.</p>
<p>| Parameter | Type | Description |</p>
<p>|-----------|------|-------------|</p>
<p>| <code>name</code> | <code>str</code> | Unique theme name (e.g. <code>"ocean"</code>, <code>"sunset"</code>) |</p>
<p>| <code>variables</code> | <code>dict[str, str]</code> | Dict with at least <code>{"accent": "#hexcolor"}</code> |</p>
<p>See CSS Architecture for all available CSS variables.</p>
<p>---</p>
<h3>`aiui.set_custom_js(path)`</h3>
<p>Inject a local JavaScript file into the UI. Reads the file at <code>path</code> and</p>
<p>serves it at <code>/custom.js</code>. A <code>&lt;script src="/custom.js"&gt;</code> tag is injected</p>
<p>into the host HTML <strong>after</strong> the plugin loader, so <code>window.aiui</code> and all</p>
<p>registry APIs (<code>registerView</code>, <code>registerComponent</code>) are ready when your</p>
<p>code runs.</p>
<p>| Parameter | Type | Description |</p>
<p>|-----------|------|-------------|</p>
<p>| <code>path</code> | <code>str \| Path</code> | Local filesystem path to a <code>.js</code> file |</p>
<p>Raises <code>FileNotFoundError</code> if the path does not exist.</p>
<p>Where <code>plugin.js</code> uses the client-side extension APIs:</p>
<p>---</p>
<h3>`aiui.register_component_schema(component_type, schema)`</h3>
<p>Register a JSON Schema contract for a component dict. Built-in schemas</p>
<p>are auto-derived from every <code>aiui.ui.*</code> builder at startup; user schemas</p>
<p>take priority and are merged on top.</p>
<p>| Parameter | Type | Description |</p>
<p>|-----------|------|-------------|</p>
<p>| <code>component_type</code> | <code>str</code> | Component type string (e.g. <code>"timeline"</code>) |</p>
<p>| <code>schema</code> | <code>dict</code> | JSON Schema dict (Draft 2020-12 compatible) |</p>
<h3>`aiui.get_component_schemas()`</h3>
<p>Returns the merged registry as a <code>dict[str, dict]</code>. Also available as a</p>
<p>JSON endpoint: <code>GET /api/components/schemas</code>.</p>
<p>---</p>
<h3>`aiui.prompt(question, *, options=None, timeout=300.0)`</h3>
<p>Pause the agent and wait for the user to answer. Preferred entry point</p>
<p>for interactive agent flows — supersedes the legacy <code>AskUserMessage</code></p>
<p>class.</p>
<p>| Parameter | Type | Description |</p>
<p>|-----------|------|-------------|</p>
<p>| <code>question</code> | <code>str</code> | Text shown to the user. |</p>
<p>| <code>options</code> | <code>list[str] \| None</code> | Optional list of choices. When given, the user picks one; otherwise they type free text. |</p>
<p>| <code>timeout</code> | <code>float</code> | Seconds to wait before giving up. Default 300 (5 min). |</p>
<p>Returns a <code>PromptResult</code> dataclass (<code>text</code>, <code>choice</code>, <code>message_id</code>).</p>
<p>The result is truthy when the user answered, falsy on timeout.</p>
<p>---</p>
<h3>`aiui.error(content, *, details=None)`</h3>
<p>Emit an error message to the chat. A thin helper around <code>Message</code> with</p>
<p><code>metadata={"kind": "error"}</code> — keeps the public surface small.</p>
<p>---</p>
<h3>`aiui.configure(*, datastore=None, branding=None, theme=None, chat=None, custom_css=None, custom_js=None, style=None)`</h3>
<p>One-stop configuration function. Every keyword is optional, so you only</p>
<p>set what you need. Replaces the dozen individual <code>set_*</code> setters for</p>
<p>most common cases (the <code>set_*</code> functions remain for advanced control).</p>
<p>| Parameter | Type | Description |</p>
<p>|-----------|------|-------------|</p>
<p>| <code>datastore</code> | <code>str</code> | Storage backend: <code>"memory"</code>, <code>"json"</code>, <code>"json:/path"</code>, <code>"sdk"</code>, <code>"sdk:/path"</code>. |</p>
<p>| <code>branding</code> | <code>dict</code> | Forwarded to <code>set_branding(...)</code>. Keys: <code>title</code>, <code>logo</code>, <code>subtitle</code>. |</p>
<p>| <code>theme</code> | <code>dict</code> | Forwarded to <code>set_theme(...)</code>. Keys: <code>preset</code>, <code>dark</code>/<code>dark_mode</code>, <code>radius</code>, <code>brand_color</code>. |</p>
<p>| <code>chat</code> | <code>dict</code> | Forwarded to <code>set_chat_features(...)</code>. Keys: <code>feedback</code>, <code>mode</code>, plus any chat-feature flag. |</p>
<p>| <code>custom_css</code>| <code>str \| Path</code> | Path to a CSS file; same as <code>set_custom_css</code>. |</p>
<p>| <code>custom_js</code> | <code>str \| Path</code> | Path to a JS file; same as <code>set_custom_js</code>. |</p>
<p>| <code>style</code> | <code>str</code> | UI style — <code>"chat"</code>, <code>"dashboard"</code>, etc. |</p>
<p>---</p>
<h2>Callback Decorators</h2>
<h3>`@aiui.reply`</h3>
<p>Handle incoming chat messages. This is the core callback.</p>
<p>The <code>message</code> object has:</p>
<li><code>message.content</code> — user's text</li>
<li><code>message.session_id</code> — session identifier</li>
<li><code>message.images</code> — attached images (if any)</li>
<p>---</p>
<h3>`@aiui.welcome`</h3>
<p>Send a welcome message when a user connects.</p>
<p>---</p>
<h3>`@aiui.goodbye`</h3>
<p>Cleanup when a user disconnects.</p>
<p>---</p>
<h3>`@aiui.starters`</h3>
<p>Define conversation starters shown to new users.</p>
<p>---</p>
<h3>`@aiui.profiles`</h3>
<p>Define chat profiles (agent personas users can choose).</p>
<p>---</p>
<h3>`@aiui.page(slug, title, icon, group, order)`</h3>
<p>Register a custom dashboard page.</p>
<p>---</p>
<h3>`@aiui.on(event)`</h3>
<p>Listen for server events.</p>
<p>---</p>
<h3>`@aiui.login`</h3>
<p>Handle authentication.</p>
<p>---</p>
<h3>`@aiui.settings`</h3>
<p>Provide user settings.</p>
<p>---</p>
<h3>`@aiui.resume`</h3>
<p>Resume interrupted sessions.</p>
<p>---</p>
<h3>`@aiui.surface_action(surface_id)`</h3>
<p>Handle user actions from an A2UI surface (button clicks, form submits).</p>
<p>---</p>
<h2>Message Functions</h2>
<p>Async functions for sending messages to the user. Call inside callback handlers.</p>
<p>| Function | Purpose |</p>
<p>|----------|---------|</p>
<p>| <code>await aiui.say(text)</code> | Send a complete message |</p>
<p>| <code>await aiui.stream(text)</code> | Stream a response progressively |</p>
<p>| <code>await aiui.stream_token(token)</code> | Stream token-by-token |</p>
<p>| <code>await aiui.think(text)</code> | Show a thinking indicator |</p>
<p>| <code>await aiui.ask(question)</code> | Ask user a question (returns answer) |</p>
<p>| <code>await aiui.image(url)</code> | Send an image |</p>
<p>| <code>await aiui.audio(url)</code> | Send audio |</p>
<p>| <code>await aiui.video(url)</code> | Send video |</p>
<p>| <code>await aiui.file(url)</code> | Send a file |</p>
<p>| <code>await aiui.action_buttons(buttons)</code> | Show action buttons |</p>
<p>| <code>await aiui.tool(name, data)</code> | Show tool call result |</p>
<p>---</p>
<h2>UI Components</h2>
<p>Build custom page layouts with UI components.</p>
<p>| Component | Usage |</p>
<p>|-----------|-------|</p>
<p>| <code>aiui.layout(children)</code> | Root container for a page |</p>
<p>| <code>aiui.card(title, *, value, footer)</code> | Metric/stat card with title, value, and optional footer |</p>
<p>| <code>aiui.columns(children)</code> | Horizontal column layout |</p>
<p>| <code>aiui.chart(data, type)</code> | Chart (line, bar, pie) |</p>
<p>| <code>aiui.table(headers, rows)</code> | Data table |</p>
<p>| <code>aiui.text(content)</code> | Text block |</p>
<p>See Component API Reference for all 48 components.</p>
<p>---</p>
<h2>Data Classes</h2>
<p>| Class | Purpose |</p>
<p>|-------|---------|</p>
<p>| <code>aiui.Message</code> | Incoming/outgoing message |</p>
<p>| <code>aiui.AskUserMessage</code> | User response to <code>ask()</code> |</p>
<p>| <code>aiui.Step</code> | Processing step indicator |</p>
<p>| <code>aiui.BaseDataStore</code> | Abstract datastore interface |</p>
<p>| <code>aiui.MemoryDataStore</code> | In-memory store |</p>
<p>| <code>aiui.JSONFileDataStore</code> | Persistent JSON file store |</p>
<p>| <code>aiui.BaseProvider</code> | Abstract AI provider interface |</p>
<p>| <code>aiui.PraisonAIProvider</code> | PraisonAI provider implementation |</p>
<p>| <code>aiui.RunEvent</code> | Streaming event |</p>
<p>| <code>aiui.RunEventType</code> | Event type enum |</p>
<p>---</p>
<h2>Feature Protocol</h2>
<p>Register custom features that appear in the dashboard.</p>
<p>| Function | Purpose |</p>
<p>|----------|---------|</p>
<p>| <code>aiui.register_feature(feature)</code> | Register a feature |</p>
<p>| <code>aiui.get_features()</code> | List all features |</p>
<p>| <code>aiui.get_feature(name)</code> | Get a specific feature |</p>
<p>| <code>aiui.auto_register_defaults()</code> | Auto-register built-in features |</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-74
View File
@@ -1,74 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Create a new session." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Sessions API Reference | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/sessions" />
<meta property="og:title" content="Sessions API Reference | PraisonAIUI Docs" />
<meta property="og:description" content="Create a new session." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/sessions" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Sessions API Reference | PraisonAIUI Docs" />
<meta name="twitter:description" content="Create a new session." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Sessions API Reference", "description": "Create a new session.", "url": "https://ui.praison.ai/docs/api/sessions", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<h2>Endpoints</h2>
<h3>`GET /sessions`</h3>
<p>List all sessions.</p>
<p><strong>Response:</strong></p>
<h3>`GET /sessions/{session_id}`</h3>
<p>Get full session data including messages.</p>
<p><strong>Response:</strong></p>
<p>---</p>
<h3>`GET /sessions/{session_id}/runs`</h3>
<p>Get message history for a session.</p>
<p><strong>Response:</strong></p>
<p>---</p>
<h3>`DELETE /sessions/{session_id}`</h3>
<p>Delete a session.</p>
<p><strong>Response:</strong></p>
<p>---</p>
<h3>`POST /run`</h3>
<p>Send a message and receive streaming response via SSE.</p>
<p><strong>Request:</strong></p>
<p>If <code>session_id</code> is omitted or <code>null</code>, a new session is created automatically.</p>
<p><strong>Response:</strong> Server-Sent Events stream:</p>
<p>---</p>
<h3>`POST /cancel`</h3>
<p>Cancel an active run.</p>
<p><strong>Request:</strong></p>
<p>---</p>
<h3>`GET /health`</h3>
<p>Server health check.</p>
<p><strong>Response:</strong></p>
<p>---</p>
<h3>`GET /agents`</h3>
<p>List registered agents.</p>
<p><strong>Response:</strong></p>
<h2>Error Responses</h2>
<p>All endpoints return <code>404</code> when a session is not found:</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-99
View File
@@ -1,99 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Test all 16 PraisonAIUI feature APIs using curl. Each example creates real data and verifies backend processing." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>API Testing Guide | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/testing" />
<meta property="og:title" content="API Testing Guide | PraisonAIUI Docs" />
<meta property="og:description" content="Test all 16 PraisonAIUI feature APIs using curl. Each example creates real data and verifies backend processing." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/testing" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="API Testing Guide | PraisonAIUI Docs" />
<meta name="twitter:description" content="Test all 16 PraisonAIUI feature APIs using curl. Each example creates real data and verifies backend processing." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "API Testing Guide", "description": "Test all 16 PraisonAIUI feature APIs using curl. Each example creates real data and verifies backend processing.", "url": "https://ui.praison.ai/docs/api/testing", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Test all 16 PraisonAIUI feature APIs using curl. Each example creates real data and verifies backend processing.</p>
<h2>Quick Start</h2>
<h2>CLI Integration Tests (`aiui test`)</h2>
<p>PraisonAIUI includes built-in integration tests via</p>
<p><code>aiui test</code>. These run against a live server and verify chat, memory, sessions,</p>
<p>and API endpoint health.</p>
<h3>Quick Start</h3>
<h3>Available Subcommands</h3>
<p>| Command | What It Tests |</p>
<p>|---------|---------------|</p>
<p>| <code>aiui test endpoints</code> | API endpoint availability (/health, /api/features, /api/sessions, /api/chat) |</p>
<p>| <code>aiui test chat</code> | Message sending, session history isolation, context recall |</p>
<p>| <code>aiui test memory</code> | Cross-session persistent memory (store + recall facts) |</p>
<p>| <code>aiui test sessions</code> | Session file persistence (survives server restarts) |</p>
<p>| <code>aiui test all</code> | Runs all of the above in sequence |</p>
<h3>Options</h3>
<li><code>--server</code> / <code>-s</code> — Server URL (default: <code>http://127.0.0.1:8082</code>)</li>
<li><code>--timeout</code> / <code>-t</code> — Response timeout in seconds (default: <code>30</code>)</li>
<h3>Example Output</h3>
<h3>Test Details</h3>
<p><strong>Endpoints</strong> (6 checks, 2 optional skips):</p>
<li><code>GET /api/features</code> — Feature registry health</li>
<li><code>GET /api/sessions</code> — Session listing</li>
<li><code>GET /api/chat/history</code> — Empty session history</li>
<li><code>POST /api/chat/send</code> — Chat message dispatch</li>
<li><code>GET /api/provider/health</code> — _(optional, skipped if no provider)_</li>
<li><code>GET /api/provider/agents</code> — _(optional, skipped if no provider)_</li>
<li><code>GET /health</code> — Server health check</li>
<p><strong>Chat</strong> (8 checks):</p>
<li>Sends a message to Session A, verifies response in history</li>
<li>Creates Session B, verifies history isolation (no cross-session leakage)</li>
<li>Verifies Session A retains context from earlier messages</li>
<p><strong>Memory</strong> (2 checks):</p>
<li>Sends a fact to Session 1 ("remember my name")</li>
<li>Asks a recall question in Session 2, verifies cross-session memory</li>
<p><strong>Sessions</strong> (4 checks):</p>
<li>Sends a message and verifies session file is created on disk</li>
<li>Verifies history API returns persisted messages</li>
<p>---</p>
<h2>Running the Full API Test Suite</h2>
<p>Use the example at <code>examples/python/14-all-features/app.py</code> which tests all 16 features programmatically:</p>
<h2>Expected Results</h2>
<p>| Feature | Endpoints | Expected |</p>
<p>|---------|-----------|----------|</p>
<p>| Channels | 4 | All 200/201 |</p>
<p>| Agents | 3+ | 201 create, 200 list, 501 run (no praisonaiagents) |</p>
<p>| Approvals | 6 | Auto-approve low-risk, manual approve high-risk |</p>
<p>| Jobs | 3 | 202 submit, 200 list/stats |</p>
<p>| Schedules | 2 | 201 create, 200 list |</p>
<p>| Usage | 4+ | 201 track, 200 summary with by_model breakdown |</p>
<p>| Skills | 2 | 18 skills, 7 categories |</p>
<p>| Config | 5 | Schema, defaults, validate, runtime set/get |</p>
<p>| Auth | 4 | API key generation, multi-mode auth |</p>
<p>| OpenAI API | 2 | 11 endpoints, 13 models |</p>
<p>| Logs | 2 | 5 log levels |</p>
<p>| Sessions | 3 | State save/get/preview |</p>
<p>| Memory | 6 | List, add, search, context, session-scoped, status |</p>
<p>| Hooks | 1 | 200 (empty until registered) |</p>
<p>| Workflows | 1 | 200 (empty until created) |</p>
<p>| Features | 1 | 16 features registered |</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-54
View File
@@ -1,54 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Complete API reference for the TypeScript/React runtime." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>TypeScript SDK Reference | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/api/typescript" />
<meta property="og:title" content="TypeScript SDK Reference | PraisonAIUI Docs" />
<meta property="og:description" content="Complete API reference for the TypeScript/React runtime." />
<meta property="og:url" content="https://ui.praison.ai/docs/api/typescript" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="TypeScript SDK Reference | PraisonAIUI Docs" />
<meta name="twitter:description" content="Complete API reference for the TypeScript/React runtime." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "TypeScript SDK Reference", "description": "Complete API reference for the TypeScript/React runtime.", "url": "https://ui.praison.ai/docs/api/typescript", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Complete API reference for the TypeScript/React runtime.</p>
<h2>Installation</h2>
<h2>Core Functions</h2>
<h3>createAIUI</h3>
<p>Initialize the runtime with manifests.</p>
<h3>resolveTemplate</h3>
<p>Match a route to a template.</p>
<h2>SlotRegistry</h2>
<p>Register custom components for slots.</p>
<h2>Next.js Adapter</h2>
<h3>withAIUI</h3>
<p>Wrap your Next.js config:</p>
<h3>getDocsPageProps</h3>
<p>Get props for docs pages:</p>
<h2>Types</h2></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Concepts - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Concepts | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/concepts" />
<meta property="og:title" content="Concepts | PraisonAIUI Docs" />
<meta property="og:description" content="Concepts - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta property="og:url" content="https://ui.praison.ai/docs/concepts" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Concepts | PraisonAIUI Docs" />
<meta name="twitter:description" content="Concepts - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Concepts", "description": "Concepts - Documentation for PraisonAIUI - YAML-driven website generator", "url": "https://ui.praison.ai/docs/concepts", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-90
View File
@@ -1,90 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PraisonAIUI has two complementary integration layers with the praisonai backend. They solve different problems and run side-by-side." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Architecture: AG-UI Protocol vs Gateway Integration | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/concepts/architecture" />
<meta property="og:title" content="Architecture: AG-UI Protocol vs Gateway Integration | PraisonAIUI Docs" />
<meta property="og:description" content="PraisonAIUI has two complementary integration layers with the praisonai backend. They solve different problems and run side-by-side." />
<meta property="og:url" content="https://ui.praison.ai/docs/concepts/architecture" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Architecture: AG-UI Protocol vs Gateway Integration | PraisonAIUI Docs" />
<meta name="twitter:description" content="PraisonAIUI has two complementary integration layers with the praisonai backend. They solve different problems and run side-by-side." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Architecture: AG-UI Protocol vs Gateway Integration", "description": "PraisonAIUI has two complementary integration layers with the praisonai backend. They solve different problems and run side-by-side.", "url": "https://ui.praison.ai/docs/concepts/architecture", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>PraisonAIUI has <strong>two complementary integration layers</strong> with the praisonai backend. They solve different problems and run side-by-side.</p>
<h2>Protocol Stack</h2>
<p>AG-UI sits alongside MCP and A2A in the agentic protocol stack:</p>
<p>| Protocol | Purpose |</p>
<p>|----------|---------|</p>
<p>| <strong>MCP</strong> | Gives agents tools |</p>
<p>| <strong>A2A</strong> | Agent-to-agent communication |</p>
<p>| <strong>AG-UI</strong> | Agent-to-user-interface (streaming) |</p>
<p>| <strong>Gateway</strong> | Infrastructure management (channels, nodes, instances) |</p>
<h2>AG-UI — The Conversation Layer</h2>
<p><a href="https://ag-ui.com/">AG-UI</a> is an <strong>open, event-based protocol</strong> by CopilotKit that standardizes how agent backends stream events to frontends. PraisonAI implements it at <code>praisonaiagents/ui/agui/</code>.</p>
<p><strong>What it does:</strong> Streams ~16 standard event types (text deltas, tool calls, state sync, generative UI) over SSE.</p>
<p><strong>Who uses it:</strong> LangGraph, CrewAI, Google ADK, Microsoft Agent Framework, AWS Strands, Mastra, Pydantic AI, LlamaIndex, AG2, and PraisonAI.</p>
<h3>Usage</h3>
<p><strong>Frontend compatibility:</strong> CopilotKit, or any AG-UI-compatible client.</p>
<h2>Gateway Integration — The Operations Layer</h2>
<p>The gateway integration connects PraisonAIUI's dashboard features to the live <code>WebSocketGateway</code> backend for infrastructure management.</p>
<p><strong>What it does:</strong> CRUD for channels, nodes, instances; live bot status; heartbeat monitoring.</p>
<h3>How It Works</h3>
<h3>Key Files</h3>
<p>| File | Purpose |</p>
<p>|------|---------|</p>
<p>| <code>features/_gateway_ref.py</code> | Thread-safe singleton holding reference to the live gateway |</p>
<p>| <code>features/channels.py</code> | Channel CRUD + live status enrichment from gateway |</p>
<p>| <code>features/nodes.py</code> | Node CRUD + gateway health enrichment |</p>
<p>| <code>integration.py</code> | Calls <code>set_gateway()</code> on start, clears on stop |</p>
<p>| <code>config_store.py</code> | Unified <code>~/.praisonaiui/config.yaml</code> — single source of truth for all feature state |</p>
<h3>API Endpoints</h3>
<p>| Endpoint | Methods | Description |</p>
<p>|----------|---------|-------------|</p>
<p>| <code>/api/channels</code> | GET, POST | List/create channels |</p>
<p>| <code>/api/channels/{id}</code> | GET, PUT, DELETE | Channel CRUD |</p>
<p>| <code>/api/channels/{id}/toggle</code> | POST | Enable/disable |</p>
<p>| <code>/api/channels/{id}/status</code> | GET | Live running status |</p>
<p>| <code>/api/channels/platforms</code> | GET | Supported platforms |</p>
<p>| <code>/api/nodes</code> | GET, POST | List/register nodes |</p>
<p>| <code>/api/nodes/{id}</code> | GET, PUT, DELETE | Node CRUD |</p>
<p>| <code>/api/nodes/{id}/status</code> | GET | Node status + gateway enrichment |</p>
<p>| <code>/api/nodes/{id}/agents</code> | GET, PUT | Agent bindings |</p>
<p>| <code>/api/instances</code> | GET | Connected instances |</p>
<p>| <code>/api/instances/heartbeat</code> | POST | Presence heartbeat |</p>
<h2>Using Both Together</h2>
<p><code>AIUIGateway.start()</code> in <code>integration.py</code> mounts the gateway and dashboard REST API on one server. Chat uses the built-in WebSocket/SSE <code>RunEvent</code> protocol; AG-UI is mounted separately via <code>AguiFeature</code> when enabled:</p>
<h2>Summary</h2>
<p>| | AG-UI (<code>/agui</code>) | Gateway (<code>/api/*</code>) |</p>
<p>|---|---|---|</p>
<p>| <strong>Layer</strong> | Conversation | Operations |</p>
<p>| <strong>Transport</strong> | SSE (server-sent events) | REST + WebSocket |</p>
<p>| <strong>Purpose</strong> | Stream agent responses to users | Manage channels, nodes, instances |</p>
<p>| <strong>Frontend</strong> | CopilotKit / AG-UI clients | PraisonAIUI React dashboard |</p>
<p>| <strong>Protocol</strong> | Open standard (~16 event types) | Internal REST API |</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-104
View File
@@ -1,104 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Complete guide to the aiui.template.yaml configuration schema." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>YAML Configuration | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/concepts/configuration" />
<meta property="og:title" content="YAML Configuration | PraisonAIUI Docs" />
<meta property="og:description" content="Complete guide to the aiui.template.yaml configuration schema." />
<meta property="og:url" content="https://ui.praison.ai/docs/concepts/configuration" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="YAML Configuration | PraisonAIUI Docs" />
<meta name="twitter:description" content="Complete guide to the aiui.template.yaml configuration schema." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "YAML Configuration", "description": "Complete guide to the aiui.template.yaml configuration schema.", "url": "https://ui.praison.ai/docs/concepts/configuration", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Complete guide to the <code>aiui.template.yaml</code> configuration schema.</p>
<h2>Overview</h2>
<p>PraisonAIUI uses a single YAML file to configure your entire site. This file defines:</p>
<li><strong>Site metadata</strong> - Title, description, theme</li>
<li><strong>Content sources</strong> - Where to find your docs</li>
<li><strong>Components</strong> - Reusable UI elements</li>
<li><strong>Templates</strong> - Page layouts with slots</li>
<li><strong>Routes</strong> - URL patterns to template mappings</li>
<h2>Schema Version</h2>
<p>Always specify the schema version:</p>
<h2>Site Configuration</h2>
<p>&gt; <strong>Note</strong>: The <code>ui</code> field is a theming hint. Components are UI-agnostic and use CSS classes you can style with any framework.</p>
<h2>Component Dependencies</h2>
<p>Auto-install shadcn components at build time:</p>
<p>When you run <code>aiui build</code>, any missing components are automatically installed via <code>npx shadcn add</code>.</p>
<h2>Content Sources</h2>
<h2>Components</h2>
<p>Define reusable components:</p>
<h3>Built-in Component Types</h3>
<p>| Type | Description |</p>
<p>|------|-------------|</p>
<p>| <code>Header</code> | Site header with logo, nav, CTA |</p>
<p>| <code>Footer</code> | Site footer |</p>
<p>| <code>DocsSidebar</code> | Documentation sidebar navigation |</p>
<p>| <code>Toc</code> | Table of contents |</p>
<p>| <code>DocContent</code> | Rendered markdown content |</p>
<h2>Templates</h2>
<p>Templates combine a layout with slot assignments:</p>
<h3>Layouts</h3>
<p>| Layout | Description |</p>
<p>|--------|-------------|</p>
<p>| <code>ThreeColumnLayout</code> | Sidebar + Content + TOC |</p>
<p>| <code>TwoColumnLayout</code> | Sidebar + Content |</p>
<p>| <code>CenteredLayout</code> | Centered content, no sidebar |</p>
<p>| <code>FullWidthLayout</code> | Full width content |</p>
<p>| <code>FlexibleLayout</code> | WordPress-style widget zones |</p>
<h2>Widget Zones</h2>
<p>Place widgets in layout zones without modifying markdown:</p>
<h3>Available Zones</h3>
<p>| Zone | Description |</p>
<p>|------|-------------|</p>
<p>| <code>header</code> | Top header |</p>
<p>| <code>topNav</code> | Below header nav |</p>
<p>| <code>hero</code> | Hero banners |</p>
<p>| <code>leftSidebar</code> | Left column |</p>
<p>| <code>main</code> | Main content |</p>
<p>| <code>rightSidebar</code> | Right column |</p>
<p>| <code>bottomNav</code> | Pagination area |</p>
<p>| <code>footer</code> | Footer widgets |</p>
<h3>Built-in Widgets</h3>
<p>| Widget | Description |</p>
<p>|--------|-------------|</p>
<p>| <code>StatsCard</code> | Metrics display |</p>
<p>| <code>QuickLinks</code> | Navigation links |</p>
<p>| <code>Newsletter</code> | Email signup |</p>
<p>| <code>HeroBanner</code> | Hero section |</p>
<p>| <code>SocialLinks</code> | Social icons |</p>
<p>| <code>Copyright</code> | Copyright text |</p>
<p>See Widget Zones for full documentation.</p>
<h2>Routes</h2>
<p>Map URL patterns to templates:</p>
<p>Route matching uses glob patterns:</p>
<li><code>*</code> - Single segment</li>
<li><code>**</code> - Multiple segments</li>
<h2>Complete Example</h2></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-135
View File
@@ -1,135 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PraisonAIUI uses a provider protocol — a simple abstraction that lets you plug in any AI backend." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Providers | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/concepts/providers" />
<meta property="og:title" content="Providers | PraisonAIUI Docs" />
<meta property="og:description" content="PraisonAIUI uses a provider protocol — a simple abstraction that lets you plug in any AI backend." />
<meta property="og:url" content="https://ui.praison.ai/docs/concepts/providers" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Providers | PraisonAIUI Docs" />
<meta name="twitter:description" content="PraisonAIUI uses a provider protocol — a simple abstraction that lets you plug in any AI backend." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Providers", "description": "PraisonAIUI uses a provider protocol — a simple abstraction that lets you plug in any AI backend.", "url": "https://ui.praison.ai/docs/concepts/providers", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>PraisonAIUI uses a <strong>provider protocol</strong> — a simple abstraction that lets you plug in any AI backend.</p>
<h2>Architecture</h2>
<p>The provider protocol is the <strong>only contract</strong> between the frontend and any AI backend. All dashboard pages (<code>/api/overview</code>, <code>/api/config</code>, <code>/api/logs</code>, etc.) are provider-agnostic — they always work regardless of which backend is active. The provider only handles agent execution (<code>run()</code>), agent listing (<code>list_agents()</code>), and health checks (<code>health()</code>).</p>
<h2>How It Works</h2>
<p>1. User sends a message → <code>POST /run</code></p>
<p>2. Server calls <code>provider.run(message)</code> on the active provider</p>
<p>3. Provider yields <code>RunEvent</code> objects (start, content, tool calls, reasoning, completion)</p>
<p>4. Server serialises each <code>RunEvent</code> to an SSE <code>data:</code> frame</p>
<p>5. Frontend <code>useSSE.ts</code> parses events and renders components</p>
<h2>Built-in Provider: PraisonAI</h2>
<p>PraisonAI is the default provider. It wraps the <code>@aiui.reply</code> callback system:</p>
<p>No extra config needed — <code>PraisonAIProvider</code> is used automatically.</p>
<h3>Agent Tools and Reflection</h3>
<p>The default provider resolves tools for agents using <code>ToolResolver</code> from the <code>praisonai</code> package. Agents created via the CRUD API or <code>~/.praisonaiui/config.yaml</code> get their tool names (strings) automatically resolved to callable Python functions:</p>
<p>When no tools are configured, the provider gives agents sensible defaults (<code>internet_search</code>).</p>
<p>Agents also support <code>reflection: true</code> (default) for self-reflection mode, where the agent evaluates its own response quality before returning.</p>
<h2>Swapping Providers</h2>
<h2>Writing a Custom Provider</h2>
<p>Implement <code>BaseProvider.run()</code> — that's it:</p>
<h3>Inline media (images, video, files)</h3>
<p>Any provider can attach rich media to chat messages using `<code>MESSAGE_ELEMENT</code>`</p>
<p>events. The UI renders them inline and persists them in session history.</p>
<p>Tool results from PraisonAI agents are also detected automatically when they</p>
<p>match OpenAI image shapes (`<code>{"data": [{"url": "..."}]}</code>`) or explicit element</p>
<p>dicts — no provider code required.</p>
<p>Callback handlers can use `<code>Message.add_image()</code><code> or </code><code>await aiui.image(url)</code>`</p>
<p>and the default `<code>PraisonAIProvider</code><code> maps those to </code><code>MESSAGE_ELEMENT</code>` events.</p>
<p>Full architecture, data flows, and tests: Image Preview in Chat.</p>
<h3>With Tool Calls and Reasoning</h3>
<h2>RunEvent Reference</h2>
<p>Every event has a <code>type</code> field and optional payload fields:</p>
<p>| Field | Type | Used By |</p>
<p>|-------|------|---------|</p>
<p>| <code>type</code> | <code>RunEventType</code> | All events |</p>
<p>| <code>content</code> | <code>str</code> | <code>RUN_COMPLETED</code>, <code>RUN_CONTENT</code> |</p>
<p>| <code>token</code> | <code>str</code> | <code>RUN_CONTENT</code> (streaming) |</p>
<p>| <code>name</code> | <code>str</code> | <code>TOOL_CALL_*</code> |</p>
<p>| <code>args</code> | <code>dict</code> | <code>TOOL_CALL_STARTED</code> |</p>
<p>| <code>result</code> | <code>any</code> | <code>TOOL_CALL_COMPLETED</code> |</p>
<p>| <code>step</code> | <code>str</code> | <code>REASONING_STEP</code> |</p>
<p>| <code>error</code> | <code>str</code> | <code>RUN_ERROR</code> |</p>
<p>| <code>agent_name</code> | <code>str</code> | Multi-agent events |</p>
<p>| <code>extra_data</code> | <code>dict</code> | Custom payload (includes <code>element</code> for <code>message_element</code>) |</p>
<h3>Event Types (27 total)</h3>
<p>=== "Agent Events"</p>
<p>| Type | Description |</p>
<p>|------|-------------|</p>
<p>| <code>run_started</code> | Agent run begins |</p>
<p>| <code>run_content</code> | Streaming token or content chunk |</p>
<p>| <code>run_completed</code> | Agent run finished |</p>
<p>| <code>run_error</code> | Error occurred |</p>
<p>| <code>run_cancelled</code> | User cancelled |</p>
<p>| <code>tool_call_started</code> | Tool invocation started |</p>
<p>| <code>tool_call_completed</code> | Tool returned result |</p>
<p>| <code>reasoning_started</code> | Thinking begun |</p>
<p>| <code>reasoning_step</code> | Individual reasoning step |</p>
<p>| <code>reasoning_completed</code> | Thinking finished |</p>
<p>| <code>memory_update_started</code> | Memory write begun |</p>
<p>| <code>memory_update_completed</code> | Memory write done |</p>
<p>| <code>updating_memory</code> | Memory being updated |</p>
<p>| <code>run_paused</code> | Run paused (e.g. waiting for user) |</p>
<p>| <code>run_continued</code> | Run resumed |</p>
<p>| <code>message_element</code> | Inline media element (image, video, file, etc.) — see Image Preview in Chat |</p>
<p>=== "Team Events"</p>
<p>| Type | Description |</p>
<p>|------|-------------|</p>
<p>| <code>team_run_started</code> | Team run begins |</p>
<p>| <code>team_run_content</code> | Team streaming content |</p>
<p>| <code>team_run_completed</code> | Team run finished |</p>
<p>| <code>team_run_error</code> | Team error |</p>
<p>| <code>team_run_cancelled</code> | Team cancelled |</p>
<p>| <code>team_tool_call_started</code> | Team tool call started |</p>
<p>| <code>team_tool_call_completed</code> | Team tool call done |</p>
<p>| <code>team_reasoning_started</code> | Team reasoning begun |</p>
<p>| <code>team_reasoning_step</code> | Team reasoning step |</p>
<p>| <code>team_reasoning_completed</code> | Team reasoning done |</p>
<p>| <code>team_memory_update_started</code> | Team memory update started |</p>
<p>| <code>team_memory_update_completed</code> | Team memory update done |</p>
<h2>API Summary</h2>
<h3>`BaseProvider` (abstract)</h3>
<p>: Subclass and implement <code>run()</code> to create a custom provider.</p>
<p>| Method | Description |</p>
<p>|--------|-------------|</p>
<p>| <code>run(message, *, session_id, agent_name, <strong>kw)</code> | </strong>Required.** Async generator yielding <code>RunEvent</code> objects |</p>
<p>| <code>list_agents()</code> | Optional. Returns list of available agents |</p>
<p>| <code>health()</code> | Optional. Returns health check dict |</p>
<h3>`RunEvent` (dataclass)</h3>
<p>: Structured event with <code>type: RunEventType</code> and optional payload fields (see table above).</p>
<li><code>to_dict()</code> → serialise to JSON-compatible dict matching the frontend <code>SSEEvent</code> interface</li>
<h3>`RunEventType` (enum)</h3>
<p>: 27 string values matching the frontend <code>types.ts</code> — see Agent Events and Team Events tabs above.</p>
<h3>Helper Functions</h3>
<p>| Function | Description |</p>
<p>|----------|-------------|</p>
<p>| <code>praisonaiui.set_provider(provider)</code> | Set the active provider |</p>
<p>| <code>praisonaiui.get_provider()</code> | Get the active provider (lazy-inits <code>PraisonAIProvider</code>) |</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-55
View File
@@ -1,55 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Understanding the slot system and built-in components." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Slots &amp; Components | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/concepts/slots" />
<meta property="og:title" content="Slots &amp; Components | PraisonAIUI Docs" />
<meta property="og:description" content="Understanding the slot system and built-in components." />
<meta property="og:url" content="https://ui.praison.ai/docs/concepts/slots" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Slots &amp; Components | PraisonAIUI Docs" />
<meta name="twitter:description" content="Understanding the slot system and built-in components." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Slots & Components", "description": "Understanding the slot system and built-in components.", "url": "https://ui.praison.ai/docs/concepts/slots", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Understanding the slot system and built-in components.</p>
<h2>Slot System</h2>
<p>Slots are named insertion points in layouts. Each template assigns components to slots:</p>
<h2>Built-in Components</h2>
<h3>Header</h3>
<p>Site header with logo, navigation, and CTA.</p>
<h3>Footer</h3>
<p>Site footer with links and copyright.</p>
<h3>DocsSidebar</h3>
<p>Documentation navigation sidebar.</p>
<h3>Toc</h3>
<p>Table of contents for the current page.</p>
<h3>DocContent</h3>
<p>Renders the markdown content for the current page.</p>
<h2>Custom Components</h2>
<p>Override built-in components using the TypeScript SDK:</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-69
View File
@@ -1,69 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Learn how templates and layouts work in PraisonAIUI." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Templates &amp; Layouts | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/concepts/templates" />
<meta property="og:title" content="Templates &amp; Layouts | PraisonAIUI Docs" />
<meta property="og:description" content="Learn how templates and layouts work in PraisonAIUI." />
<meta property="og:url" content="https://ui.praison.ai/docs/concepts/templates" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Templates &amp; Layouts | PraisonAIUI Docs" />
<meta name="twitter:description" content="Learn how templates and layouts work in PraisonAIUI." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Templates & Layouts", "description": "Learn how templates and layouts work in PraisonAIUI.", "url": "https://ui.praison.ai/docs/concepts/templates", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Learn how templates and layouts work in PraisonAIUI.</p>
<h2>Overview</h2>
<p>Templates define the structure of your pages by combining:</p>
<li>A <strong>layout</strong> - The structural container</li>
<li><strong>Slots</strong> - Pluggable content areas</li>
<h2>Layouts</h2>
<p>PraisonAIUI provides four layouts:</p>
<p>| Layout | Description |</p>
<p>|--------|-------------|</p>
<p>| <code>ThreeColumnLayout</code> | Sidebar + Content + TOC (classic docs) |</p>
<p>| <code>TwoColumnLayout</code> | Sidebar + Content (no TOC) |</p>
<p>| <code>CenteredLayout</code> | Centered content, no sidebar |</p>
<p>| <code>FullWidthLayout</code> | Full-width content |</p>
<h3>ThreeColumnLayout</h3>
<p>The classic documentation layout with sidebar and TOC.</p>
<h3>TwoColumnLayout</h3>
<p>Sidebar + Content without the right TOC column.</p>
<h3>CenteredLayout</h3>
<p>Centered content with no sidebar, ideal for articles/blogs.</p>
<h3>FullWidthLayout</h3>
<p>Full-width content without sidebar.</p>
<h2>Defining Templates</h2>
<h2>Slot Assignment</h2>
<p>Slots can be assigned in two ways:</p>
<h3>Reference (ref)</h3>
<p>Point to a component defined in the <code>components</code> section:</p>
<h3>Direct Type</h3>
<p>Use a component type directly:</p>
<h3>Null (hide)</h3>
<p>Remove a slot entirely:</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Examples - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Examples | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/examples" />
<meta property="og:title" content="Examples | PraisonAIUI Docs" />
<meta property="og:description" content="Examples - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta property="og:url" content="https://ui.praison.ai/docs/examples" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Examples | PraisonAIUI Docs" />
<meta name="twitter:description" content="Examples - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Examples", "description": "Examples - Documentation for PraisonAIUI - YAML-driven website generator", "url": "https://ui.praison.ai/docs/examples", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-47
View File
@@ -1,47 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Complex configurations and customization patterns." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Advanced Examples | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/examples/advanced" />
<meta property="og:title" content="Advanced Examples | PraisonAIUI Docs" />
<meta property="og:description" content="Complex configurations and customization patterns." />
<meta property="og:url" content="https://ui.praison.ai/docs/examples/advanced" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Advanced Examples | PraisonAIUI Docs" />
<meta name="twitter:description" content="Complex configurations and customization patterns." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Advanced Examples", "description": "Complex configurations and customization patterns.", "url": "https://ui.praison.ai/docs/examples/advanced", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Complex configurations and customization patterns.</p>
<h2>Multiple Templates</h2>
<p>Different layouts for different sections:</p>
<h2>Route-Level Overrides</h2>
<p>Override slots for specific pages:</p>
<h2>Custom Components</h2>
<p>Register custom components in TypeScript:</p>
<h2>Dark Mode with Custom Colors</h2></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-76
View File
@@ -1,76 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Simple examples to get started with PraisonAIUI." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Basic Examples | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/examples/basic" />
<meta property="og:title" content="Basic Examples | PraisonAIUI Docs" />
<meta property="og:description" content="Simple examples to get started with PraisonAIUI." />
<meta property="og:url" content="https://ui.praison.ai/docs/examples/basic" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Basic Examples | PraisonAIUI Docs" />
<meta name="twitter:description" content="Simple examples to get started with PraisonAIUI." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Basic Examples", "description": "Simple examples to get started with PraisonAIUI.", "url": "https://ui.praison.ai/docs/examples/basic", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Simple examples to get started with PraisonAIUI.</p>
<h2>Python Examples Reference</h2>
<p>Each example teaches exactly <strong>one new concept</strong> — no overlap.</p>
<p>| # | Name | Unique Concept | Run |</p>
<p>|---|---|---|---|</p>
<p>| 01 | chat | <code>@reply</code> + <code>aiui.say()</code> — minimal hello-world | <code>aiui run app.py</code> |</p>
<p>| 02 | chat-app | Full lifecycle callbacks (<code>@welcome</code>, <code>@button</code>, <code>@profiles</code>, <code>@starters</code>, <code>@goodbye</code>) | <code>aiui run app.py</code> |</p>
<p>| 03 | chat-with-ai | OpenAI streaming via <code>stream_token()</code> | <code>aiui run app.py</code> |</p>
<p>| 04 | chat-with-praisonai | PraisonAI Agent, <code>asyncio.to_thread()</code>, <code>stream=False</code> | <code>aiui run app.py</code> |</p>
<p>| 05 | agent-playground | Multi-agent <code>@profiles</code> switching | <code>aiui run app.py</code> |</p>
<p>| 06 | dashboard | <code>@page</code> decorator, <code>@on("event")</code> syntax | <code>aiui run app.py</code> |</p>
<p>| 07 | provider-praisonai | Custom <code>BaseProvider</code> subclass, <code>RunEvent</code> protocol | <code>aiui run app.py</code> |</p>
<p>| 08 | streaming | PraisonAI Agent streaming via <code>stream_emitter</code> | <code>aiui run app.py</code> |</p>
<p>| 09 | widget | Copilot/sidebar mode | <code>aiui run app.py</code> |</p>
<p>| 10 | feature-showcase | All protocol features seeded, <code>create_app()</code> | <code>python app.py</code> |</p>
<p>| 11 | ui-integration | Gradio ASGI mount, Streamlit iframe, REST embedding | <code>python app.py</code> |</p>
<p>| 12 | agent-dashboard | OpenClaw-style rendered HTML admin panel | <code>python app.py</code> |</p>
<p>| 13 | real-dashboard | Production dashboard with seeded data | <code>python app.py</code> |</p>
<p>| 14 | all-features | Comprehensive 16-feature API test suite | <code>python app.py</code> |</p>
<p>| 15 | dashboard-test | Dashboard component rendering tests | <code>aiui run app.py</code> |</p>
<p>| 16 | gateway-integration | Gateway WebSocket integration | <code>aiui run app.py</code> |</p>
<p>| 17 | three-column-demo | Three-column layout with sidebar + TOC | <code>aiui run app.py</code> |</p>
<p>| 18 | full-chat | Full-featured chat with all options enabled | <code>aiui run app.py</code> |</p>
<p>| 19 | components-showcase | All 48 UI components demonstrated | <code>aiui run app.py</code> |</p>
<p>| 20 | email-channel | Email channel integration | <code>aiui run app.py</code> |</p>
<p>| 21 | agentmail-bot | Agentmail bot integration | <code>aiui run app.py</code> |</p>
<p>| 22 | agentmail-channel | Agentmail channel setup | <code>aiui run app.py</code> |</p>
<p>| 23 | e2e-components-test | End-to-end component testing | <code>aiui run app.py</code> |</p>
<p>| 24 | custom-design | Custom CSS design system with <code>set_custom_css()</code> | <code>aiui run app.py</code> |</p>
<p>| 25 | clean-chat | Clean chat UI — <code>sidebar=False</code>, <code>page_header=False</code>, blue theme | <code>aiui run app.py</code> |</p>
<p>| 26 | custom-theme-chat | Custom theme registration via <code>register_theme()</code> | <code>aiui run app.py</code> |</p>
<p>| 27 | multica-style | Floating chat window, collapsible sidebar, indigo theme | <code>aiui run app.py</code> |</p>
<h2>Minimal Docs Site</h2>
<p>The simplest configuration:</p>
<h2>With Header and Footer</h2>
<p>Add branding:</p>
<h2>Directory Structure</h2></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-39
View File
@@ -1,39 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Features - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Features | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features" />
<meta property="og:title" content="Features | PraisonAIUI Docs" />
<meta property="og:description" content="Features - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta property="og:url" content="https://ui.praison.ai/docs/features" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Features | PraisonAIUI Docs" />
<meta name="twitter:description" content="Features - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Features", "description": "Features - Documentation for PraisonAIUI - YAML-driven website generator", "url": "https://ui.praison.ai/docs/features", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-93
View File
@@ -1,93 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PraisonAIUI hosts A2UI v0.9 surfaces: agents push structured UI messages to a live canvas while users chat in the same window or on a full-page workspace." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>A2UI canvas — agent-driven UI | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/a2ui-canvas" />
<meta property="og:title" content="A2UI canvas — agent-driven UI | PraisonAIUI Docs" />
<meta property="og:description" content="PraisonAIUI hosts A2UI v0.9 surfaces: agents push structured UI messages to a live canvas while users chat in the same window or on a full-page workspace." />
<meta property="og:url" content="https://ui.praison.ai/docs/features/a2ui-canvas" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="A2UI canvas — agent-driven UI | PraisonAIUI Docs" />
<meta name="twitter:description" content="PraisonAIUI hosts A2UI v0.9 surfaces: agents push structured UI messages to a live canvas while users chat in the same window or on a full-page workspace." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "A2UI canvas — agent-driven UI", "description": "PraisonAIUI hosts A2UI v0.9 surfaces: agents push structured UI messages to a live canvas while users chat in the same window or on a full-page workspace.", "url": "https://ui.praison.ai/docs/features/a2ui-canvas", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>PraisonAIUI hosts <strong>A2UI v0.9</strong> surfaces: agents push structured UI messages to a live canvas while users chat in the same window or on a full-page workspace.</p>
<p>For dashboard extension patterns (views, plugins, layout JSON), see Agent UI host.</p>
<h2>Quick start</h2>
<p>Run the full example: <code>examples/python/30-a2ui-canvas/app.py</code>.</p>
<h2>Dashboard pages</h2>
<p>| Page id | Route | Purpose |</p>
<p>|---------|-------|---------|</p>
<p>| <code>chat-canvas</code> | <code>/chat-canvas</code> | Split view — chat left, live A2UI preview right |</p>
<p>| <code>chat</code> | <code>/chat</code> | Vanilla chat (unchanged) |</p>
<p>| <code>canvas</code> | <code>/canvas</code> | Full-page surface workspace |</p>
<p>Enable the split preview with <code>set_chat_preview</code>. Settings appear in <code>/ui-config.json</code> as <code>chat.preview: { enabled, surfaceId, width }</code>.</p>
<h2>Agent integration</h2>
<p>Agents should call <strong><code>send_a2ui_messages</code></strong> (from <code>praisonaiagents.tools.a2ui_tools</code>) with A2UI message dicts:</p>
<p>Wrap the tool with <strong><code>coerce_a2ui_tool_messages</code></strong> so common LLM argument shapes still work:</p>
<p><code>coerce_a2ui_tool_messages</code> accepts:</p>
<li>A JSON string or list of message dicts</li>
<li>A dict with a <code>messages</code> key</li>
<li>A bare <code>components</code> list (wrapped in <code>updateComponents</code>)</li>
<li>A single component dict (wrapped in <code>updateComponents</code>)</li>
<li>Missing <code>createSurface</code> (inserted automatically for the given <code>surface_id</code>)</li>
<p>Tool results are detected by <code>a2ui_utils</code> and ingested into the surface store; connected clients receive WebSocket <code>a2ui_surface</code> events.</p>
<h2>HTTP API</h2>
<p>| Method | Path | Behaviour |</p>
<p>|--------|------|-----------|</p>
<p>| <code>GET</code> | <code>/api/surfaces</code> | List surfaces and message counts |</p>
<p>| <code>GET</code> | <code>/api/surfaces/{id}</code> | Surface state; <strong>200 with <code>{ messages: [] }</code></strong> if not created yet (empty canvas is normal) |</p>
<p>| <code>POST</code> | <code>/api/surfaces/{id}/messages</code> | Append or replace messages (<code>replace: true</code> in body) |</p>
<p>| <code>POST</code> | <code>/api/surfaces/{id}/actions</code> | User action from a button/component |</p>
<p>| <code>DELETE</code> | <code>/api/surfaces/{id}</code> | Clear surface |</p>
<p>Realtime updates use the existing dashboard WebSocket (<code>a2ui_surface</code> payload).</p>
<h2>CLI</h2>
<p>Manage surfaces against a running server (<code>--server</code> / <code>AIUI_SERVER</code>, default <code>http://127.0.0.1:8000</code>):</p>
<p><code>messages.json</code> must contain <code>{ "messages": [ ... ] }</code>.</p>
<h2>Frontend modules</h2>
<p>Shared dashboard JS (lazy-loaded with <code>chat-canvas</code>):</p>
<p>| Module | Role |</p>
<p>|--------|------|</p>
<p>| <code>surface-utils.js</code> | Load surface, WebSocket sync, post actions |</p>
<p>| <code>canvas-preview.js</code> | Right-hand preview panel |</p>
<p>| <code>a2ui-mapper.js</code> | Default DOM mapper (Text, Button, Column, Row, Card, …) |</p>
<p>| <code>plugins/views/chat-canvas.js</code> | Composes chat + preview without modifying <code>chat.js</code> |</p>
<p>Override rendering: <code>window.aiui.registerSurfaceRenderer("main", fn)</code>.</p>
<h2>Troubleshooting</h2>
<p>| Symptom | Likely cause | Fix |</p>
<p>|---------|--------------|-----|</p>
<p>| Chat works but canvas stays empty | Agent did not call <code>send_a2ui_messages</code> | Strengthen instructions; wrap tool with <code>coerce_a2ui_tool_messages</code> |</p>
<p>| Tool error / invalid JSON | LLM passed wrong shape | Use coercion wrapper; include schema prompt from <code>praisonaiagents.ui.a2ui.adapter</code> |</p>
<p>| Preview shows raw JSON | Component type not in <code>a2ui-mapper</code> | Extend mapper or use supported components |</p>
<p>| <code>GET /api/surfaces/main</code> empty | Normal before first push | Push via agent or <code>aiui surface push</code> |</p>
<p>| Button click does nothing | No <code>@aiui.surface_action</code> handler | Register handler for that <code>surface_id</code> |</p>
<h2>Related</h2>
<li>Agent UI host — <code>registerSurfaceRenderer</code>, layout tiers</li>
<li>Python API — <code>set_chat_preview</code></li>
<li>Python API — <code>@aiui.surface_action</code></li></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-133
View File
@@ -1,133 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PraisonAIUI can host any AI agent backend behind a modular dashboard shell: pages, views, layout components, optional plugins, and branding — without forking th" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Agent UI host — modular dashboard shell | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/agent-ui-host" />
<meta property="og:title" content="Agent UI host — modular dashboard shell | PraisonAIUI Docs" />
<meta property="og:description" content="PraisonAIUI can host any AI agent backend behind a modular dashboard shell: pages, views, layout components, optional plugins, and branding — without forking th" />
<meta property="og:url" content="https://ui.praison.ai/docs/features/agent-ui-host" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Agent UI host — modular dashboard shell | PraisonAIUI Docs" />
<meta name="twitter:description" content="PraisonAIUI can host any AI agent backend behind a modular dashboard shell: pages, views, layout components, optional plugins, and branding — without forking th" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Agent UI host — modular dashboard shell", "description": "PraisonAIUI can host any AI agent backend behind a modular dashboard shell: pages, views, layout components, optional plugins, and branding — without forking th", "url": "https://ui.praison.ai/docs/features/agent-ui-host", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>PraisonAIUI can host any AI agent backend behind a <strong>modular dashboard shell</strong>: pages, views, layout components, optional plugins, and branding — without forking the frontend.</p>
<h2>Architecture</h2>
<p><strong>Extension priority</strong> (first match wins):</p>
<p>1. <code>window.aiui.registerView(pageId, …)</code></p>
<p>2. Dashboard manifest plugins (<code>dashboard-plugins/*/manifest.json</code>)</p>
<p>3. Built-in view modules (<code>plugins/views/*.js</code> via <code>BUILTIN_VIEWS</code>)</p>
<p>4. Server <code>aiui.layout()</code> JSON from <code>@aiui.page()</code></p>
<p>5. <code>window.aiui.registerComponent(type, …)</code> inside <code>renderComponent</code></p>
<p>6. Generic JSON fallback viewer</p>
<h2>Video Studio</h2>
<p>For YAML scene authoring with an external PraisonAI Video engine, see Video Studio.</p>
<h2>Quick start (external agent)</h2>
<p>See <code>examples/python/external-agent-dashboard/app.py</code>.</p>
<h2>`window.aiui` extension API</h2>
<p>| API | Purpose |</p>
<p>|-----|---------|</p>
<p>| <code>version</code> | Shell protocol version (<code>'1'</code>) |</p>
<p>| <code>registerView(pageId, renderFn, cleanup?)</code> | Replace or add a full page renderer |</p>
<p>| <code>registerComponent(type, renderFn)</code> | Override a layout component type |</p>
<p>| <code>registerSurfaceRenderer(surfaceId, renderFn)</code> | Custom A2UI surface renderer |</p>
<p>| <code>selectPage(pageId)</code> | Navigate programmatically (e.g. open full canvas) |</p>
<p>| <code>registerSlot(name, renderFn)</code> | Inject DOM into named slots |</p>
<p>| <code>sdk.fetchJSON(url, opts?)</code> | Authenticated fetch helper |</p>
<p>| <code>sdk.el(tag, attrs?, children?)</code> | Small DOM builder |</p>
<p>| <code>sdk.themeVar('--db-*', fallback?)</code> | Read theme CSS variables |</p>
<p>| <code>sdk.createBoard(root, { fetch, pollMs? })</code> | Live board with optional polling |</p>
<h3>Slots</h3>
<p>| Slot id | Where it renders |</p>
<p>|---------|------------------|</p>
<p>| <code>shell:sidebar:footer</code> | Bottom of sidebar (default: health hint) |</p>
<p>| <code>page:{pageId}:toolbar</code> | Right side of page header |</p>
<p>Register only what you need; omit slots you do not use.</p>
<h2>Layout components (Python → JS)</h2>
<p>Define pages with <code>@aiui.page()</code> returning <code>aiui.layout([...])</code>. Types are implemented once in <code>ui.py</code> and <code>dashboard.js</code>.</p>
<p><strong>Kanban / board:</strong> use <code>aiui.board(columns=[...])</code>. Columns contain <code>id</code>, <code>title</code>, and <code>cards</code> (from <code>aiui.card()</code> or dicts). The shell renders via <code>renderBoard</code>, composing existing card renderers (DRY).</p>
<h2>A2UI surfaces (agent-driven UI)</h2>
<p>Three tiers work together:</p>
<p>| Tier | Mechanism | Use case |</p>
<p>|------|-----------|----------|</p>
<p>| Dashboard | <code>aiui.layout()</code> → <code>_components</code> | Python-authored pages |</p>
<p>| A2UI | <code>send_a2ui_messages</code> → <code>SurfaceHost</code> | Agent-generated UI in chat/canvas |</p>
<p>| AG-UI | <code>POST /agui</code> SSE | CopilotKit / external clients |</p>
<p>Register an empty canvas page:</p>
<p>Or use <code>@aiui.surface_action("main")</code> for button callbacks.</p>
<p><strong>Full guide:</strong> A2UI canvas — chat-canvas split view, <code>send_a2ui_messages</code>, HTTP/CLI, <code>coerce_a2ui_tool_messages</code>, troubleshooting. Example: <code>examples/python/30-a2ui-canvas/</code>.</p>
<h2>Optional dashboard modules</h2>
<p>Load heavy built-ins only when listed:</p>
<p>This adds <code>jobs.js</code>, <code>auth.js</code>, or <code>api.js</code> to the plugin chain and maps them in <code>BUILTIN_VIEWS</code>. <code>feedback</code> is always available as a built-in view when the page is enabled.</p>
<h2>Third-party dashboard plugins</h2>
<p>Place folders under:</p>
<li><code>~/.praisonai/dashboard-plugins/{name}/</code></li>
<li>Or <code>src/praisonaiui/templates/frontend/dashboard-plugins/{name}/</code> (shipped examples)</li>
<p>Each plugin needs <code>manifest.json</code> + <code>index.js</code> (optional <code>styles.css</code>):</p>
<p>The server exposes:</p>
<li><code>GET /api/dashboard/plugins</code> — manifest list</li>
<li><code>GET /dashboard-plugins/{name}/{path}</code> — static assets</li>
<p>Plugins register views in <code>index.js</code>:</p>
<p>Sample: <code>sample-board</code>.</p>
<h2>Agent plugins vs dashboard plugins</h2>
<p>| System | Location | Purpose |</p>
<p>|--------|----------|---------|</p>
<p>| Agent plugins | <code>~/.praisonai/plugins/</code> | Python agent extensions |</p>
<p>| Dashboard plugins | <code>~/.praisonai/dashboard-plugins/</code> | JS UI tabs |</p>
<p>See PraisonAI package integration for backend wiring, jobs API, and deployment.</p>
<h2>Granular control — opt-in / opt-out</h2>
<p>| What you control | How | Example |</p>
<p>|------------------|-----|---------|</p>
<p>| UI mode | <code>aiui.set_style(...)</code> | <code>"dashboard"</code>, <code>"chat"</code>, <code>"docs"</code> |</p>
<p>| Sidebar pages | <code>aiui.set_pages([ids])</code> whitelist | <code>["chat", "sessions"]</code> |</p>
<p>| Hide built-ins | YAML <code>pages.disabled: [...]</code> | Blacklist in server |</p>
<p>| Sidebar on/off | <code>set_dashboard(sidebar=False)</code> | Chat-only full width |</p>
<p>| Page title bar | <code>set_dashboard(page_header=False)</code> | Cleaner surface |</p>
<p>| Optional modules | <code>set_dashboard(modules=[...])</code> | <code>["jobs"]</code> only |</p>
<p>| Third-party tabs | Install chosen <code>dashboard-plugins/</code> folders | Manifest per plugin |</p>
<p>| Shell chrome | <code>registerSlot</code> | Header/footer widgets |</p>
<p>| Look only | <code>set_theme</code>, <code>set_branding</code>, <code>set_custom_css</code> | White-label |</p>
<p>| Replace one page | <code>registerView(pageId, ...)</code> | Override built-in |</p>
<p>| Board UI | <code>aiui.board()</code> or plugin | Not in default nav |</p>
<p><strong>Note:</strong> <code>@aiui.page()</code> custom pages are <strong>not</strong> filtered by <code>set_pages()</code> — only built-in dashboard pages are. Remove custom pages from code to hide them.</p>
<h3>Example profiles</h3>
<p>CLI: <code>aiui pages ids</code> lists built-in page ids for whitelists.</p>
<h2>DRY rules for contributors</h2>
<p>1. Add new layout types in <strong><code>ui.py</code></strong> and one <code>case</code> in <strong><code>dashboard.js</code></strong>.</p>
<p>2. Page-specific UI belongs in **<code>plugins/views/*.js</code>**, delegating to shared modules (<code>jobs.js</code>, etc.) via thin wrappers.</p>
<p>3. Reuse <strong><code>_helpers.js</code></strong> (<code>pageToolbar</code>, <code>filterChips</code>, <code>searchInput</code>, <code>modalShell</code>, <code>toast</code>).</p>
<p>4. Boards compose <strong><code>card</code></strong> / <strong><code>columns</code></strong> — do not duplicate card markup in plugins.</p>
<h2>Related files</h2>
<p>| File | Role |</p>
<p>|------|------|</p>
<p>| <code>praisonai-package-integration.md</code> | Praison backend wiring |</p>
<p>| <code>server.py</code> | Pages API, <code>set_dashboard</code>, plugin chain |</p>
<p>| <code>dashboard_plugins.py</code> | Manifest discovery and static routes |</p>
<p>| <code>dashboard.js</code> | Shell, registries, renderers |</p>
<p>| <code>schema/models.py</code> | <code>DashboardConfig.modules</code>, <code>plugin_dirs</code> |</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-79
View File
@@ -1,79 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Upload files to include with chat messages — PDFs, CSVs, images, and text files up to 50 MB per file. Uploaded files are automatically processed and their conte" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Chat Attachments | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/attachments" />
<meta property="og:title" content="Chat Attachments | PraisonAIUI Docs" />
<meta property="og:description" content="Upload files to include with chat messages — PDFs, CSVs, images, and text files up to 50 MB per file. Uploaded files are automatically processed and their conte" />
<meta property="og:url" content="https://ui.praison.ai/docs/features/attachments" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Chat Attachments | PraisonAIUI Docs" />
<meta name="twitter:description" content="Upload files to include with chat messages — PDFs, CSVs, images, and text files up to 50 MB per file. Uploaded files are automatically processed and their conte" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Chat Attachments", "description": "Upload files to include with chat messages — PDFs, CSVs, images, and text files up to 50 MB per file. Uploaded files are automatically processed and their conte", "url": "https://ui.praison.ai/docs/features/attachments", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Upload files to include with chat messages — PDFs, CSVs, images, and text files up to 50 MB per file. Uploaded files are <strong>automatically processed</strong> and their content is injected into the agent's prompt.</p>
<p>!Attachments Panel</p>
<h2>Quick Start</h2>
<p>The agent will receive the extracted PDF text prepended to the user message and can answer questions about the document's content.</p>
<h2>How It Works</h2>
<h2>File Processing by Type</h2>
<p>When you send a chat message with <code>attachment_ids</code>, each attachment is processed based on its type:</p>
<p>| File Type | Processing | What the Agent Sees |</p>
<p>|-----------|-----------|-------------------|</p>
<p>| <strong>PDF</strong> (<code>.pdf</code>) | Text extracted via <code>pypdf</code> | Full text content prepended to prompt |</p>
<p>| <strong>Images</strong> (<code>.png</code>, <code>.jpg</code>, etc.) | Passed to SDK multimodal handler | Image sent as base64 to vision-capable LLMs |</p>
<p>| <strong>Text/Code</strong> (<code>.txt</code>, <code>.py</code>, <code>.csv</code>, etc.) | File contents read directly | Full file content prepended to prompt |</p>
<p>!!! note "PDF Dependency"</p>
<p>PDF text extraction requires the <code>pypdf</code> package (<code>pip install pypdf</code>). If <code>pypdf</code> is not installed, a fallback message is shown instead of the extracted text. <code>pypdf</code> is included in PraisonAIUI's dependencies by default.</p>
<h2>Supported File Types</h2>
<p>| Category | Extensions |</p>
<p>|----------|-----------|</p>
<p>| Documents | <code>.pdf</code>, <code>.doc</code>, <code>.docx</code>, <code>.txt</code>, <code>.md</code> |</p>
<p>| Data | <code>.csv</code>, <code>.json</code>, <code>.xml</code>, <code>.yaml</code>, <code>.yml</code> |</p>
<p>| Images | <code>.png</code>, <code>.jpg</code>, <code>.jpeg</code>, <code>.gif</code>, <code>.webp</code>, <code>.svg</code> |</p>
<p>| Code | <code>.py</code>, <code>.js</code>, <code>.ts</code>, <code>.html</code>, <code>.css</code> |</p>
<p>!!! warning "Blocked Types"</p>
<p>Executable files (<code>.exe</code>, <code>.sh</code>, <code>.bat</code>, <code>.cmd</code>, <code>.com</code>) are rejected by default.</p>
<h2>Configuration</h2>
<h2>REST API</h2>
<p>| Endpoint | Method | Description |</p>
<p>|----------|--------|-------------|</p>
<p>| <code>/api/chat/attachments</code> | POST | Upload a file |</p>
<p>| <code>/api/chat/attachments</code> | GET | List attachments for a session |</p>
<p>| <code>/api/chat/attachments/{id}</code> | DELETE | Delete an attachment |</p>
<h3>Upload</h3>
<p>Response:</p>
<h3>Send Chat with Attachments</h3>
<p>The <code>attachment_ids</code> array links uploaded files to the chat message. The server extracts content from each attachment and prepends it to the user's message before sending to the agent.</p>
<h3>List</h3>
<h2>WebSocket</h2>
<p>When sending messages via WebSocket, include <code>attachment_ids</code> in the message payload:</p>
<h2>Related</h2>
<li>Gateway Chat — Chat interface</li>
<li>Sessions — Session management</li></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-56
View File
@@ -1,56 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="PraisonAIUI supports a four-layer integration model so standalone mode and SDK-integrated mode can share the same feature APIs." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Backend Integration Contract | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/backend-integration" />
<meta property="og:title" content="Backend Integration Contract | PraisonAIUI Docs" />
<meta property="og:description" content="PraisonAIUI supports a four-layer integration model so standalone mode and SDK-integrated mode can share the same feature APIs." />
<meta property="og:url" content="https://ui.praison.ai/docs/features/backend-integration" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Backend Integration Contract | PraisonAIUI Docs" />
<meta name="twitter:description" content="PraisonAIUI supports a four-layer integration model so standalone mode and SDK-integrated mode can share the same feature APIs." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Backend Integration Contract", "description": "PraisonAIUI supports a four-layer integration model so standalone mode and SDK-integrated mode can share the same feature APIs.", "url": "https://ui.praison.ai/docs/features/backend-integration", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>PraisonAIUI supports a four-layer integration model so standalone mode and SDK-integrated mode can share the same feature APIs.</p>
<h2>Four Layers</h2>
<p>1. <strong>Feature API layer</strong></p>
<p>Endpoints live in feature modules and expose stable HTTP/CLI behaviour.</p>
<p>2. <strong>Feature manager layer</strong></p>
<p>Each feature manager keeps local fallback logic for standalone operation.</p>
<p>3. <strong>Backend factory layer</strong></p>
<p><code>praisonaiui.backends</code> provides optional injected factories (<code>get_workflow_runner()</code>, <code>get_hooks_lister()</code>, <code>get_usage_query()</code>, etc.).</p>
<p>4. <strong>SDK/runtime layer</strong></p>
<p>PraisonAI or praisonaiagents implementations are used when injected or importable.</p>
<h2>Injection Contract</h2>
<li>Injected backends are optional and must be callable.</li>
<li>Features must keep local fallbacks when injected backends are absent or fail.</li>
<li>Backend call signatures should remain minimal and dict/list based.</li>
<li>Integration should not introduce hard imports in feature modules when a fallback already exists.</li>
<h2>Operational Rule</h2>
<p>When integrated, wrappers should inject backend callables at startup; when standalone, features should run without any backend injection.</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
@@ -1,78 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="BeautifulUI (MIT, Shane Levine / Turbo) is a copy-paste / shadcn-registry library of React primitives for AI-native interfaces: thinking traces, streaming answe" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>BeautifulUI Integration Strategy | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/beautifului-integration" />
<meta property="og:title" content="BeautifulUI Integration Strategy | PraisonAIUI Docs" />
<meta property="og:description" content="BeautifulUI (MIT, Shane Levine / Turbo) is a copy-paste / shadcn-registry library of React primitives for AI-native interfaces: thinking traces, streaming answe" />
<meta property="og:url" content="https://ui.praison.ai/docs/features/beautifului-integration" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="BeautifulUI Integration Strategy | PraisonAIUI Docs" />
<meta name="twitter:description" content="BeautifulUI (MIT, Shane Levine / Turbo) is a copy-paste / shadcn-registry library of React primitives for AI-native interfaces: thinking traces, streaming answe" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "BeautifulUI Integration Strategy", "description": "BeautifulUI (MIT, Shane Levine / Turbo) is a copy-paste / shadcn-registry library of React primitives for AI-native interfaces: thinking traces, streaming answe", "url": "https://ui.praison.ai/docs/features/beautifului-integration", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>&gt; <strong>Epic:</strong> <a href="https://github.com/MervinPraison/PraisonAIUI/issues/292">#292</a> — BeautifulUI integration strategy for AI-native dashboard UX.</p>
<p>&gt; This is the durable, agreed strategy that the linked child issues execute against.</p>
<p><a href="https://www.beautifului.dev/">BeautifulUI</a> (MIT, Shane Levine / Turbo) is a <strong>copy-paste / shadcn-registry</strong> library of React primitives for AI-native interfaces: thinking traces, streaming answers with inline sources, HITL approval cards, tool chips, task rows, context chunks, diff/records tables, prompt bars, and a reference chat harness.</p>
<p>There is <strong>no published npm package</strong> named <code>beautiful-ui</code>. It ships only as source consumed via the shadcn registry or manual copy.</p>
<h2>1. Strategic decision</h2>
<p>BeautifulUI is adopted as <strong>vendored source</strong>, not a runtime dependency, and is exposed to dashboard plugins <strong>only through the existing <code>@praisonaiui/react</code> package</strong> — never by importing upstream file paths directly. Rollout is <strong>phased behind a feature flag</strong>, keeping the current vanilla dashboard as the fallback until parity is proven.</p>
<p>Upstream stack (Next.js 15 · React 19 · Tailwind v4 · TypeScript) is closely aligned with PraisonAIUI's <code>src/frontend</code> (Vite · React 19 · Tailwind v4 · shadcn/Radix), so primitives port with adapter work rather than a runtime bridge.</p>
<h2>2. Pillars</h2>
<p>| # | Pillar | Decision |</p>
<p>|---|--------|----------|</p>
<p>| 1 | <strong>Vendoring model</strong> | Add primitives into <code>src/frontend</code> via <code>npx shadcn add https://www.beautifului.dev/r/&lt;component&gt;.json</code>, or manual copy from <a href="https://github.com/slev12397/beautiful-ui">github.com/slev12397/beautiful-ui</a>. Pin via lockfile plus a recorded registry URL / git SHA. No <code>beautiful-ui</code> npm dependency in production builds. |</p>
<p>| 2 | <strong>Adapter layer</strong> | Map PraisonAIUI chat / approval / trace <strong>protocol events</strong> to stable internal props. Primitives sit behind <code>@praisonaiui/react</code> exports; dashboard plugins consume those exports, not upstream paths. See <a href="https://github.com/MervinPraison/PraisonAIUI/issues/294">#294</a>. |</p>
<p>| 3 | <strong>Hybrid rollout</strong> | Mount React <strong>islands</strong> (or expand <code>@praisonaiui/react</code>) for high-value surfaces first — chat streaming/thinking/tools, then approvals. Vanilla chat (<code>templates/frontend/plugins/views/chat.js</code>) stays as the flag-gated fallback until parity is proven. |</p>
<p>| 4 | <strong>Token strategy</strong> | Merge BeautifulUI foundation CSS <strong>selectively</strong> into the existing shadcn theme generation (<code>praisonaiui/themes.py</code>). One design system per page — avoid two competing token sets. |</p>
<p>| 5 | <strong>Icon licence</strong> | Upstream <code>SidebarNav</code> uses the paid <code>@central-icons-react</code>. Port nav patterns with <strong>lucide-react</strong> (already in PraisonAIUI) instead. |</p>
<h2>3. Phasing</h2>
<p>1. <strong>Spike</strong> — evaluate primitives in the dev environment, confirm React 19 / Tailwind v4 alignment. <a href="https://github.com/MervinPraison/PraisonAIUI/issues/293">#293</a></p>
<p>2. <strong>Architecture</strong> — adapter layer + upstream pin policy. <a href="https://github.com/MervinPraison/PraisonAIUI/issues/294">#294</a></p>
<p>3. <strong>CI gate</strong> — frontend build + BeautifulUI compatibility check (no frontend build gate exists today). <a href="https://github.com/MervinPraison/PraisonAIUI/issues/295">#295</a></p>
<p>4. <strong>Migrations</strong> — chat streaming / thinking / tool chips (<a href="https://github.com/MervinPraison/PraisonAIUI/issues/296">#296</a>), then the approval card (<a href="https://github.com/MervinPraison/PraisonAIUI/issues/297">#297</a>).</p>
<p>5. <strong>Docs</strong> — upgrade playbook + MIT attribution. <a href="https://github.com/MervinPraison/PraisonAIUI/issues/298">#298</a></p>
<h2>4. Risks</h2>
<p>| Risk | Mitigation |</p>
<p>|------|------------|</p>
<p>| No semver npm package | Vendor the source; pin to a recorded registry URL / git SHA in the lockfile. |</p>
<p>| Upstream breaking registry JSON | Vendoring decouples builds from live registry; re-sync is a deliberate, reviewed step. |</p>
<p>| Icon licence (<code>@central-icons-react</code> is paid) | Use lucide-react for ported nav patterns; never vendor the paid package. |</p>
<p>| Two competing design systems on one page | Selective CSS token merge into <code>themes.py</code>; adapter-only prop surface. |</p>
<p>| React / Tailwind drift | Upstream (React 19 / Tailwind v4) already matches <code>src/frontend</code>; the CI gate catches drift. |</p>
<h2>5. Out of scope</h2>
<li>Replacing the entire dashboard shell in one PR.</li>
<li>PyPI packaging of BeautifulUI.</li>
<li>iframe embedding of beautifului.dev.</li>
<li>Depending on any unpublished npm package for production builds.</li>
<h2>6. Acceptance criteria status</h2>
<li>[x] Written integration strategy agreed (vendoring + adapter + phased rollout) — this document.</li>
<li>[x] Risks documented — section 4.</li>
<li>[x] Child issues filed and prioritised — <a href="https://github.com/MervinPraison/PraisonAIUI/issues/293">#293</a>–<a href="https://github.com/MervinPraison/PraisonAIUI/issues/298">#298</a>.</li>
<li>[x] No requirement to depend on unpublished npm packages for production builds — pillar 1, out of scope.</li></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-56
View File
@@ -1,56 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Expose browser agent capabilities (CDP, Playwright) through the dashboard — run browser tasks from the UI." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Browser Automation | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/browser-automation" />
<meta property="og:title" content="Browser Automation | PraisonAIUI Docs" />
<meta property="og:description" content="Expose browser agent capabilities (CDP, Playwright) through the dashboard — run browser tasks from the UI." />
<meta property="og:url" content="https://ui.praison.ai/docs/features/browser-automation" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Browser Automation | PraisonAIUI Docs" />
<meta name="twitter:description" content="Expose browser agent capabilities (CDP, Playwright) through the dashboard — run browser tasks from the UI." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Browser Automation", "description": "Expose browser agent capabilities (CDP, Playwright) through the dashboard — run browser tasks from the UI.", "url": "https://ui.praison.ai/docs/features/browser-automation", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Expose <strong>browser agent capabilities</strong> (CDP, Playwright) through the dashboard — run browser tasks from the UI.</p>
<h2>Quick Start</h2>
<h2>How It Works</h2>
<h2>Prerequisites</h2>
<p>Browser automation requires <code>praisonai[browser]</code>:</p>
<p>This installs the Playwright and/or CDP backends.</p>
<h2>Status</h2>
<p>The status endpoint reports which backends are available:</p>
<h2>REST API</h2>
<p>| Endpoint | Method | Description |</p>
<p>|----------|--------|-------------|</p>
<p>| <code>/api/browser/status</code> | GET | Check availability and stats |</p>
<p>| <code>/api/browser/run</code> | POST | Execute a browser task |</p>
<h3>Run Task</h3>
<h2>Related</h2>
<li>Gateway Chat — Chat can trigger browser tasks via tools</li>
<li>Protocols — Feature protocol system</li></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-67
View File
@@ -1,67 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Bridge channel bot conversations (Slack, Discord, Telegram) into the Chat UI in real-time." />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Channel-to-Chat Bridge | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/channel-chat-bridge" />
<meta property="og:title" content="Channel-to-Chat Bridge | PraisonAIUI Docs" />
<meta property="og:description" content="Bridge channel bot conversations (Slack, Discord, Telegram) into the Chat UI in real-time." />
<meta property="og:url" content="https://ui.praison.ai/docs/features/channel-chat-bridge" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Channel-to-Chat Bridge | PraisonAIUI Docs" />
<meta name="twitter:description" content="Bridge channel bot conversations (Slack, Discord, Telegram) into the Chat UI in real-time." />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Channel-to-Chat Bridge", "description": "Bridge channel bot conversations (Slack, Discord, Telegram) into the Chat UI in real-time.", "url": "https://ui.praison.ai/docs/features/channel-chat-bridge", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>Bridge channel bot conversations (Slack, Discord, Telegram) into the Chat UI in real-time.</p>
<h2>Architecture</h2>
<h2>How It Works</h2>
<h3>Backend (`channels.py`)</h3>
<p><code>_attach_chat_bridge(channel_id, bot, platform)</code> is called in <code>_start_channel_bot()</code> right before the bot task is launched:</p>
<p>1. <strong><code>on_message</code> hook</strong> — Captures incoming platform messages and broadcasts <code>channel_message</code> events with sender name, platform, and icon</p>
<p>2. <strong><code>_session.chat()</code> wrapper</strong> — Wraps the agent's chat method so responses are also broadcast as <code>channel_response</code> events</p>
<p>3. <strong>Persistence</strong> — All messages saved to the datastore under session <code>channel-{channel_id}</code> for history on reload</p>
<h3>Frontend (`chat.js`)</h3>
<p>| Function | Purpose |</p>
<p>|---|---|</p>
<p>| <code>_handleChannelMessage(data)</code> | Renders incoming platform user messages; auto-switches to channel session if on fresh chat |</p>
<p>| <code>_handleChannelResponse(data)</code> | Renders agent responses from channel bots |</p>
<p>| <code>_appendChannelMsg(role, data)</code> | Creates message DOM with platform badge, icon, sender name |</p>
<p>| <code>_markSessionUnread(sessionId)</code> | Adds unread dot to sidebar for inactive channel sessions |</p>
<h2>Performance</h2>
<p>Every broadcast is dispatched via <code>asyncio.create_task()</code> — the original bot message handling is <strong>never blocked</strong>. Errors in broadcasting are logged at <code>debug</code> level and swallowed — the bot continues normally even with zero Chat UI clients connected.</p>
<h2>Session Naming</h2>
<p>Each channel gets a dedicated session: <code>channel-{channel_id}</code>. Platform icons:</p>
<p>| Platform | Icon |</p>
<p>|---|---|</p>
<p>| Slack | 💬 |</p>
<p>| Discord | 🎮 |</p>
<p>| Telegram | ✈️ |</p>
<p>| WhatsApp | 📱 |</p>
<h2>WebSocket Events</h2>
<h3>`channel_message`</h3>
<h3>`channel_response`</h3></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-55
View File
@@ -1,55 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="1. Code is submitted with a target language" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Code Execution | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/code-execution" />
<meta property="og:title" content="Code Execution | PraisonAIUI Docs" />
<meta property="og:description" content="1. Code is submitted with a target language" />
<meta property="og:url" content="https://ui.praison.ai/docs/features/code-execution" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Code Execution | PraisonAIUI Docs" />
<meta name="twitter:description" content="1. Code is submitted with a target language" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Code Execution", "description": "1. Code is submitted with a target language", "url": "https://ui.praison.ai/docs/features/code-execution", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p><strong>Sandboxed code execution</strong> with language allowlists and SDK integration. Wraps <code>praisonaiagents.tools.code.execute_code</code> when available, falls back to safe simulation mode.</p>
<h2>Quick Start</h2>
<h2>How It Works</h2>
<p>1. Code is submitted with a target language</p>
<p>2. The manager checks if the language is in the <strong>allowlist</strong> (default: python, javascript, bash)</p>
<p>3. If <code>praisonaiagents</code> is installed, delegates to <code>execute_code</code> for real execution</p>
<p>4. Otherwise returns a simulation response with the code size</p>
<h2>Configuration</h2>
<h2>REST API</h2>
<p>| Endpoint | Method | Description |</p>
<p>|----------|--------|-------------|</p>
<p>| <code>/api/code/languages</code> | GET | List supported languages |</p>
<p>| <code>/api/code/execute</code> | POST | Execute code in sandbox |</p>
<h3>POST /api/code/execute</h3>
<h2>Related</h2>
<li>Skills — Code execution tools in the skill catalog</li></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
-89
View File
@@ -1,89 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<script id="aiui-canonical-url">(function(){var p=location.pathname.replace(/\/+$/, '')||'/';if(p!==location.pathname){history.replaceState(null,'',p+location.search+location.hash);}})();</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Feature Comparison: PraisonAIUI vs OpenClaw - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<meta property="og:type" content="website" />
<meta property="og:locale" content="en_US" />
<link rel="icon" type="image/svg+xml" href="/icon.svg" />
<title>Feature Comparison: PraisonAIUI vs OpenClaw | PraisonAIUI Docs</title>
<script>
(function(){try{var t=localStorage.getItem('aiui-theme-preference');var d=true;if(t==='dark'||(t==='system'&&matchMedia('(prefers-color-scheme: dark)').matches)||(!t&&d))document.documentElement.classList.add('dark');else if(t==='light')document.documentElement.classList.remove('dark');}catch(e){}})();
</script>
<link rel="stylesheet" href="/assets/theme.css">
<script type="module" crossorigin src="/assets/index.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index.css">
<link rel="canonical" href="https://ui.praison.ai/docs/features/comparison-openclaw" />
<meta property="og:title" content="Feature Comparison: PraisonAIUI vs OpenClaw | PraisonAIUI Docs" />
<meta property="og:description" content="Feature Comparison: PraisonAIUI vs OpenClaw - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta property="og:url" content="https://ui.praison.ai/docs/features/comparison-openclaw" />
<meta property="og:type" content="article" />
<meta property="og:image" content="https://ui.praison.ai/icon.svg" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="Feature Comparison: PraisonAIUI vs OpenClaw | PraisonAIUI Docs" />
<meta name="twitter:description" content="Feature Comparison: PraisonAIUI vs OpenClaw - Documentation for PraisonAIUI - YAML-driven website generator" />
<meta name="robots" content="index, follow" />
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "TechArticle", "headline": "Feature Comparison: PraisonAIUI vs OpenClaw", "description": "Feature Comparison: PraisonAIUI vs OpenClaw - Documentation for PraisonAIUI - YAML-driven website generator", "url": "https://ui.praison.ai/docs/features/comparison-openclaw", "isPartOf": {"@type": "WebSite", "name": "PraisonAIUI Docs", "url": "https://ui.praison.ai/"}}</script>
</head>
<body>
<div id="root"><noscript><nav aria-label="Documentation"><ul><li><a href="https://ui.praison.ai/docs/health-endpoints">Health Endpoints Guide</a></li><li><a href="https://ui.praison.ai/docs/index">PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/testing">Testing</a></li><li><a href="https://ui.praison.ai/docs/adr">Adr</a></li><li><a href="https://ui.praison.ai/docs/adr/replay-view-clean-room">ADR 0001: PraisonAI Replay view, a clean-room design</a></li><li><a href="https://ui.praison.ai/docs/api">Api</a></li><li><a href="https://ui.praison.ai/docs/api/cli">CLI API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/components">Component API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/features-api">Features REST API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/health">Health API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/python">Python SDK API</a></li><li><a href="https://ui.praison.ai/docs/api/sessions">Sessions API Reference</a></li><li><a href="https://ui.praison.ai/docs/api/testing">API Testing Guide</a></li><li><a href="https://ui.praison.ai/docs/api/typescript">TypeScript SDK Reference</a></li><li><a href="https://ui.praison.ai/docs/concepts">Concepts</a></li><li><a href="https://ui.praison.ai/docs/concepts/architecture">Architecture: AG-UI Protocol vs Gateway Integration</a></li><li><a href="https://ui.praison.ai/docs/concepts/configuration">YAML Configuration</a></li><li><a href="https://ui.praison.ai/docs/concepts/providers">Providers</a></li><li><a href="https://ui.praison.ai/docs/concepts/slots">Slots &amp; Components</a></li><li><a href="https://ui.praison.ai/docs/concepts/templates">Templates &amp; Layouts</a></li><li><a href="https://ui.praison.ai/docs/examples">Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/advanced">Advanced Examples</a></li><li><a href="https://ui.praison.ai/docs/examples/basic">Basic Examples</a></li><li><a href="https://ui.praison.ai/docs/features">Features</a></li><li><a href="https://ui.praison.ai/docs/features/a2ui-canvas">A2UI canvas — agent-driven UI</a></li><li><a href="https://ui.praison.ai/docs/features/agent-ui-host">Agent UI host — modular dashboard shell</a></li><li><a href="https://ui.praison.ai/docs/features/attachments">Chat Attachments</a></li><li><a href="https://ui.praison.ai/docs/features/backend-integration">Backend Integration Contract</a></li><li><a href="https://ui.praison.ai/docs/features/beautifului-integration">BeautifulUI Integration Strategy</a></li><li><a href="https://ui.praison.ai/docs/features/browser-automation">Browser Automation</a></li><li><a href="https://ui.praison.ai/docs/features/channel-chat-bridge">Channel-to-Chat Bridge</a></li><li><a href="https://ui.praison.ai/docs/features/code-execution">Code Execution</a></li><li><a href="https://ui.praison.ai/docs/features/comparison-openclaw">Feature Comparison: PraisonAIUI vs OpenClaw</a></li><li><a href="https://ui.praison.ai/docs/features/config-hot-reload">Config Hot-Reload</a></li><li><a href="https://ui.praison.ai/docs/features/content-sources">Content Sources</a></li><li><a href="https://ui.praison.ai/docs/features/css-architecture">How the UI Looks Are Built</a></li><li><a href="https://ui.praison.ai/docs/features/dark-mode">Dark Mode</a></li><li><a href="https://ui.praison.ai/docs/features/dashboard">Dashboard</a></li><li><a href="https://ui.praison.ai/docs/features/deployment">Deployment Guide</a></li><li><a href="https://ui.praison.ai/docs/features/device-pairing">Device Pairing</a></li><li><a href="https://ui.praison.ai/docs/features/differentiation">What Makes PraisonAIUI Different</a></li><li><a href="https://ui.praison.ai/docs/features/feature-inventory">Feature Inventory</a></li><li><a href="https://ui.praison.ai/docs/features/gap-analysis">Gap Analysis — Validated Against praisonai SDK</a></li><li><a href="https://ui.praison.ai/docs/features/gateway-chat">Gateway Chat</a></li><li><a href="https://ui.praison.ai/docs/features/hot-reload">Hot Reload</a></li><li><a href="https://ui.praison.ai/docs/features/how-to-add-a-feature">How to Add a Feature to PraisonAIUI</a></li><li><a href="https://ui.praison.ai/docs/features/i18n">Internationalization (i18n)</a></li><li><a href="https://ui.praison.ai/docs/features/image-preview-chat">Image Preview in Chat</a></li><li><a href="https://ui.praison.ai/docs/features/integration-analysis">AIUI Integration — Critical Review &amp; Architecture Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/knowledge-embeddings">Knowledge Embedding Model Configuration</a></li><li><a href="https://ui.praison.ai/docs/features/marketplace">Plugin Marketplace</a></li><li><a href="https://ui.praison.ai/docs/features/media-analysis">Media Analysis</a></li><li><a href="https://ui.praison.ai/docs/features/message-elements">Message Elements</a></li><li><a href="https://ui.praison.ai/docs/features/model-fallback">Model Fallback</a></li><li><a href=Line truncated
<p>&gt; <strong>Last validated</strong>: 2026-03-06 — PraisonAIUI features verified programmatically, OpenClaw features sourced from GitHub README and docs</p>
<h2>Summary</h2>
<p>| Aspect | PraisonAIUI | OpenClaw |</p>
<p>|--------|-------------|----------|</p>
<p>| <strong>Focus</strong> | Multi-agent orchestration dashboard | Personal AI assistant gateway |</p>
<p>| <strong>Language</strong> | Python (Starlette) | TypeScript (Node.js) |</p>
<p>| <strong>Stars</strong> | Growing | 100k+ |</p>
<p>| <strong>Architecture</strong> | Protocol-driven feature modules | Gateway + Channel adapters |</p>
<p>| <strong>Registered Features</strong> | 24 | ~15 core subsystems |</p>
<p>| <strong>API Routes</strong> | 164 | ~50 (WebSocket-focused) |</p>
<p>| <strong>Channels</strong> | 8 configured, <strong>4 working bots</strong> (Discord, Telegram, Slack, WhatsApp) | <strong>22 working channels</strong> |</p>
<p>| <strong>Skills/Tools</strong> | 20+ built-in tools | <strong>13,000+ via ClawHub</strong> |</p>
<p>| <strong>Native Apps</strong> | Web only | macOS, iOS, Android |</p>
<h2>Competitive Analysis</h2>
<h3>Where PraisonAIUI is Ahead ✅</h3>
<p>| Area | Advantage |</p>
<p>|------|-----------|</p>
<p>| <strong>Multi-agent orchestration</strong> | Pipeline, Route, Parallel, Loop — no equivalent in OpenClaw |</p>
<p>| <strong>OpenAI-compatible API</strong> | Full <code>/v1/*</code> — clients can use OpenAI SDK directly |</p>
<p>| <strong>Workflow designer</strong> | 8-route workflow CRUD with run/status tracking |</p>
<p>| <strong>Approval workflows</strong> | 10-route approval system for tool execution gating |</p>
<p>| <strong>API surface area</strong> | 164 REST routes vs ~50 in OpenClaw |</p>
<p>| <strong>Config validation</strong> | Schema-driven with history tracking |</p>
<p>| <strong>Hooks system</strong> | Pre/post operation hooks with trigger API |</p>
<p>| <strong>Theme system</strong> | Dark/light/custom with CSS variable API |</p>
<p>| <strong>Protocol versioning</strong> | Client-server version negotiation |</p>
<p>| <strong>Agent CRUD</strong> | Full REST API for agent definitions |</p>
<p>| <strong>MCP tools</strong> | 64+ Model Context Protocol tools |</p>
<h3>Where OpenClaw is Ahead ⚠️</h3>
<p>| Area | Gap | Impact |</p>
<p>|------|-----|--------|</p>
<p>| <strong>Channels</strong> | 22 working vs 4 | 🟡 High — 18 niche channels missing |</p>
<p>| <strong>Skills marketplace</strong> | 13,000+ vs 0 | 🔴 Critical — massive ecosystem moat |</p>
<p>| <strong>Native apps</strong> | macOS/iOS/Android vs web-only | 🟡 High — device presence |</p>
<p>| <strong>Voice</strong> | Wake word + Talk Mode vs none | 🟡 High — hands-free interaction |</p>
<p>| <strong>Canvas (A2UI)</strong> | Agent-driven visual workspace vs partial parity | 🟡 Medium |</p>
<p>| <strong>Agent-to-agent</strong> | Sessions-based messaging vs none | 🟡 Medium |</p>
<h3>Strategic Positioning</h3>
<h3>Recommended Priorities to Close Gaps</h3>
<p>| Priority | Feature | Effort | Why |</p>
<p>|----------|---------|--------|-----|</p>
<p>| 🔴 P0 | Skills marketplace UI | High | Must have ecosystem to compete |</p>
<p>| 🟡 P1 | Wire SDK bots into dashboard UI | Medium | SDK has all 4 bots, UI just needs to launch them |</p>
<p>| 🟡 P1 | Wire SDK Memory into chat UI | Low | SDK Memory fully exists, just wire into chat |</p>
<p>| 🟡 P1 | Wire VisionAgent into chat attachments | Low | SDK has VisionAgent, wire to image uploads |</p>
<p>| 🟡 P1 | Voice/TTS in chat UI | Medium | Browser SpeechSynthesis API is free |</p>
<p>| 🟢 P2 | Agent-to-agent messaging | Medium | Builds on existing sessions + chat |</p>
<p>| 🟢 P2 | Typing indicators / presence | Low | WebSocket event additions |</p>
<p>| 🟢 P3 | Native apps (Electron/Tauri) | High | Web-first is acceptable for now |</p>
<p>| 🟢 P3 | Canvas / visual workspace | High | Unique feature but not essential |</p></noscript></div>
<script src="/plugins/plugin-loader.js"></script>
</body>
</html>
Loaded 100 of 917 files, more files were not shown because too many files have changed in this diff. Show more