release: 1.0.0-beta.6#1288
Conversation
… nits, dependabot cleanup, auto-merge rule
…-only) Restructures Dockerfile.rk3588 to FROM the taos-neko-cdp image so a future resolver flip keeps Chromium >=148 + CDP, and documents that the rkmpp userspace (mpph264enc) is not packaged for Debian trixie and needs a from-source build. No functional change yet: the rockchip RUN stays a no-op fallback and DEFAULT_NEKO_RK3588_IMAGE still points at the CDP image, so RK3588 keeps software encode until the from-source layer is validated on the Pi. Keeps it a SEPARATE image rather than folding rkmpp into the shared arm64 image: the MPP/RGA userspace + mpph264enc rank boost are SoC-specific and would break encode on non-Rockchip arm64.
… runner Multi-stage Dockerfile compiles Rockchip MPP, RGA and the gstreamer-rockchip mpph264enc plugin against trixie GStreamer 1.26 (matching the neko-cdp runtime, so the plugin ABI lines up), then layers them onto the CDP image. Adds a CI workflow that builds it on a GitHub ubuntu-24.04-arm runner and pushes ghcr.io/jaylfc/taos-neko-rk3588 -- the Pi is never used for the build, only the final validation run. Stays vendor-kernel based: mainline RK3588 H.264 encode is not ready (only out-of-tree H.265), and a kernel swap would risk the working NPU. The resolver flip stays gated on a live Pi check that mpph264enc engages.
…libdir JeffyCN/gstreamer-rockchip is no longer cloneable (moved/private). Use the BoxCloudIRL streaming-focused fork. Pin all three builds to the aarch64 multiarch libdir so the plugin lands where the runtime scans, and stage the outputs tolerantly (logged) so the final COPY does not depend on exact names. MPP + RGA already compiled clean on the arm64 runner; this fixes the last step.
neko(rk3588): base the RK3588 image on the CDP image + document rkmpp packaging
Live-validated on the Pi: the from-source taos-neko-rk3588 image registers mpph264enc and encodes 720p on the VPU (60 frames in 0.18s) when /dev/mpp_service, /dev/dri and /dev/rga are passed -- which resolve_neko_image already supplies. Point DEFAULT_NEKO_RK3588_IMAGE at the dedicated image and update the test accordingly. Software encode on the CDP image stays the fallback if the image or devices are unavailable.
Add tests/test_routes_agent_deploy.py covering validate_framework_and_ram, resolve_deploy_routing, and archive_smoke_check via the FastAPI test client. Tests exercise happy paths and error responses (400/404/409) with mocked external services. The full /api/agents/deploy endpoint requires live infrastructure (container runtime, taosmd, LLM proxy) and is not tested end-to-end.
neko(rk3588): flip resolver to the validated VPU HW-encode image (#624)
test: add endpoint tests for agent_deploy route helpers
Covers GET /config, PUT /permitted-models, PUT /persona, PATCH /settings validation, and POST /chat guard responses. Uses in-process FastAPI test client with mocked model_resolver and llm_proxy; no live infrastructure needed.
…features policy + grok disabled
Per-node hardware capability model (CPU/GPU/NPU/RAM + live status) the scheduler and placement logic build on. Built by @taOS-dev since the free owl lane could not produce the feature module (it does test cards reliably but returns empty work on net-new modules). 8 tests green.
Add endpoint tests for routes/taos_agent.py
Add tests/test_agent_registry_store.py covering: - Pure functions: _slugify, mint_canonical_id, _b64url_encode/decode, _assert_valid_transition, _row_to_dict - Token minting/verification round-trips with Ed25519 keypairs - Signing keypair persistence and idempotency - AgentRegistryStore CRUD: register, get, list_all, list_for_user, list_revoked, list_inactive - Lifecycle transitions via set_status (all valid + invalid) - Metadata updates via update (mutable + immutable fields) - Revoke (idempotent, sets revoked_at and status) - Full lifecycle round-trips - Error cases: uninitialized store, nonexistent IDs, invalid transitions
Create tests/test_feedback_store.py with 16 tests covering: - create: all fields populated, default screenshot, unique IDs, different types - get_by_id: full row retrieval, has_screenshot flag, wrong user returns None, nonexistent ID returns None - list_for_user: ordering (newest first), user scoping, screenshot blob exclusion, empty results, correct key set - constants: MAX_SCREENSHOT_LEN and MAX_BODY_LEN sanity check
Tests _new_doc_id format/uniqueness, VALID_KINDS, and full CRUD round-trips on OfficeDocStore (create, get, list, update, delete) with happy paths, edge cases, and error validation.
Covers TorrentSettings dataclass defaults, to_dict, roundtrip, and TorrentSettingsStore load/save with missing files, corrupt JSON, partial values, type coercion, directory creation, and cross-instance file sharing.
test: add unit tests for agent_registry_store
test: add unit tests for torrent_settings module
test: add unit tests for download_manager
feat(audit): project-scoped activity feed + project_id/detail columns (#105)
feat(cluster): stale-node offline sweep (non-destructive) (#897)
feat(coding): model-agnostic tool-calling loop engine (#86)
…1283) A content-filtered or error-shaped completion can return no choices or a null message; parse_completion indexed choices[0] unguarded -> IndexError/KeyError, breaking the loop's never-raise contract. Now falls back to an empty final answer. 3 tests added.
… raise Follow-up to the previous commit: response["choices"] still raised KeyError on an empty dict before the fallback; switched to .get for both choices and message access.
…istration feat(cluster): populate capability map from worker registration (#897)
feat(coding): litellm-backed model_step for the tool-calling loop (#86)
…#70) These four platform apps are unfinished and should not be offered to every user; they will be reseeded as the operator's private App Studio drafts to finish + publish on stream. Removes them from the optional-app allowlist (apps.py OPTIONAL_FRONTEND_APPS/APP_VERSIONS/APP_TRUST) so they are no longer installable, and empties the Store 'taOS Apps' catalog (optional-apps.ts). The registry manifests + React components stay for the App Studio reseed. Creative Studios remain installable. Repointed the optional-app test fixtures to coding-studio; added a de-seed assertion (not allowlisted, install 404, absent from catalog). 40 backend + 25 frontend tests green.
feat(store): de-seed X/Reddit/YouTube/GitHub from the default store (#70)
Two related fixes so there is a single Browser app that works on the Pi: 1. Remove the duplicate 'Browser (Streamed)' app. The Browser app already has a per-tab Proxy/Streamed toggle (BrowserModeToggle) that attaches the tab to a real Neko/WebRTC session via the same LiveBrowserView the standalone app imported, so StreamedBrowserApp was pure duplication. Drops the registry entry, deletes the component, removes the stale vitest exclude. 2. Fix 'the Pi isn't capable': POST /api/browser/sessions only called pick_browser_node (Tier-2 workers, never the host), so a 16GB host with no browser workers returned no_capable_node. It now uses resolve_browser_target (explicit worker -> host if RAM-capable -> best worker) and starts on the host via browser_container_runner, mirroring the already-working /sessions/mine path. 2 tests: capable host places on host; non-capable host + no workers -> 409. Browser + registry suites green.
…over when broken (#117) A failed update can leave the dashboard unreachable; this adds a one-command recovery that does not depend on the app or the web UI being healthy. - tinyagentos/rollback.py: record_pre_update writes the pre-update branch + sha to a shell-sourceable .taos-rollback file (gitignored); read_rollback_target parses it. So rollback restores BOTH the branch and the version when an update changed both. - update_runner now ALWAYS records the rollback target (after the dirty probe so the gitignored file never triggers a spurious stash), in both update_to_master and switch_to_branch -- previously a clean fast-forward left no restore point. - scripts/rollback.sh: pure git + service restart (systemd/launchd/nohup). With no args undoes the last update; 'rollback <ref>' targets a tag/branch/sha; falls back to the newest taos-pre-update-* tag for older installs. - 'taos rollback' dispatches to the script from the app entrypoint for the healthy path; the script is runnable directly when Python is broken. - 8 tests (record/read roundtrip, overwrite, shell-sourceable, quote-injection safety, updater records target). Existing updater suite green.
…1285) create_session created the session record before resolving the worker, so a failed get_worker in the worker branch returned 409 while leaving an orphaned session row in pending/idle. Move the worker lookup ahead of create_session. Test: worker-lookup failure 409s and create_session is never called.
feat(update): taos rollback -- restore previous branch + version, recover when broken (#117)
…ed-app fix(browser): one Browser app + host-capable Pi serves streamed sessions
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
👋 Thanks for the PR! This one targets See CONTRIBUTING.md for the branch model. |
|
Warning Review limit reached
More reviews will be available in 39 seconds. Learn how PR review limits work. Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file). ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (5)
📒 Files selected for processing (85)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…the invoking process Recovery script hardening from gitar review of #1287: - stash local changes (and fall back to --force checkout) so a dirty tree left by a broken update cannot abort the rollback under set -e - resolve an explicit target that only exists as origin/<branch> and recreate it locally, restoring branch as well as version - the nohup restart fallback now skips this process and its ancestors when stopping the controller, so it no longer pkills the taos CLI running it
| const merged = items | ||
| .filter((n) => !dismissedServerIds.has(n.id)) | ||
| .map((n) => (priorRead.get(n.id) ? { ...n, read: true } : n)); | ||
| // Keep every client-origin item ("notif-N") untouched, drop the old | ||
| // server items (replaced by the fresh list), de-dupe, sort newest-first. | ||
| const client = s.notifications.filter((n) => !n.id.startsWith("srv-")); | ||
| const combined = [...merged, ...client]; | ||
| // Keep every client-origin item ("notif-N") untouched, plus any archived | ||
| // server items (they must survive polls). Drop the old unarchived server | ||
| // items (replaced by the fresh list), de-dupe, sort newest-first. | ||
| const kept = s.notifications.filter( | ||
| (n) => !n.id.startsWith("srv-") || n.archived, | ||
| ); | ||
| const combined = [...merged, ...kept]; | ||
| combined.sort((a, b) => b.timestamp - a.timestamp); | ||
| return { notifications: combined.slice(0, 100) }; |
There was a problem hiding this comment.
💡 Edge Case: Archived notifications can be silently evicted by the 100-item cap
In mergeServerNotifications the combined list (active + archived/kept items) is sorted newest-first and truncated with combined.slice(0, 100). Archived notifications now share this single 100-item budget with active ones. Because archived items are typically older, they sort to the tail and are the first to be dropped when newer notifications arrive. This means the new History tab can silently lose entries the user expected to be retained, undermining the "nothing is ever deleted" intent of the History view. Consider tracking archived items separately from the live cap, or applying the cap only to non-archived items so history survival is not coupled to inbox volume.
Was this helpful? React with 👍 / 👎
| mgr = request.app.state.browser_sessions | ||
| session = await mgr.create_session( | ||
| "user", user_id, body.url, body.profile or "default" | ||
| ) | ||
| vol = f"taos-browser-{session['id']}" | ||
| auth_token = getattr(request.app.state, "browser_worker_auth_token", None) | ||
| try: | ||
| session = await mgr.start_on_worker( | ||
| session["id"], | ||
| node=node, | ||
| worker_url=worker.url, | ||
| profile_volume=f"taos-browser-{session['id']}", | ||
| auth_token=auth_token, | ||
| ) | ||
| if kind == "host": | ||
| runner = request.app.state.browser_container_runner | ||
| # _connecting_host_ip does a blocking DNS lookup; offload it so the | ||
| # event loop is not stalled while the host is resolved. | ||
| nat1to1_ip = await asyncio.to_thread(_connecting_host_ip, request) | ||
| session = await mgr.start_on_host( | ||
| session["id"], profile_volume=vol, runner=runner, nat1to1_ip=nat1to1_ip | ||
| ) |
There was a problem hiding this comment.
💡 Edge Case: Failed browser session start leaves an orphaned session row
create_session now resolves the worker before creating the session row to avoid orphans on a failed lookup (the stated fix). However, the row is still created via mgr.create_session(...) before start_on_host/start_on_worker is attempted. If that start raises BrowserWorkerError, the handler returns 502 but the just-created session record (and its taos-browser-<id> volume name) is left behind in the store, which is the same orphaned-session class the PR aims to eliminate. Unless start_on_* cleans up internally on failure, consider deleting/terminating the session row in the except BrowserWorkerError branch before returning 502.
Was this helpful? React with 👍 / 👎
| for tc in tool_calls: | ||
| fn = tc["function"] if isinstance(tc, dict) else tc.function | ||
| calls.append( | ||
| { | ||
| "id": (tc.get("id") if isinstance(tc, dict) else getattr(tc, "id", None)), | ||
| "name": (fn["name"] if isinstance(fn, dict) else fn.name), | ||
| "arguments": _parse_arguments( | ||
| fn["arguments"] if isinstance(fn, dict) else fn.arguments | ||
| ), |
There was a problem hiding this comment.
💡 Edge Case: parse_completion may KeyError on tool-call without 'arguments'
In parse_completion, when a tool call's function is a dict, arguments are read as fn["arguments"]. If a completion returns a function object/dict that omits the arguments key (some providers emit empty/partial tool calls, or streamed/aggregated responses), this raises KeyError, breaking the loop's documented never-raise resilience contract. Use fn.get("arguments") (and getattr(fn, "arguments", None) for the object branch) so _parse_arguments can fall back to {}.
Was this helpful? React with 👍 / 👎
|
Note Your trial team has used its Gitar budget, so automatic reviews are paused. Upgrade now to unlock full capacity. Comment "Gitar review" to trigger a review manually. Code Review 👍 Approved with suggestions 0 resolved / 3 findingsPromotes development to master for 1.0.0-beta.6, featuring browser unification, rollback functionality, and a new coding model tool-calling loop. Consider addressing the notification eviction cap, potential session row orphans, and KeyError risks in tool-call parsing. 💡 Edge Case: Archived notifications can be silently evicted by the 100-item cap📄 desktop/src/stores/notification-store.ts:68-79 In 💡 Edge Case: Failed browser session start leaves an orphaned session row📄 tinyagentos/routes/browser_sessions.py:137-151
💡 Edge Case: parse_completion may KeyError on tool-call without 'arguments'📄 tinyagentos/agent_tools/coding_model.py:120-128 In 🤖 Prompt for agentsOptionsDisplay: compact → Showing less information. Comment with these commands to change:
Important Your trial ends in 6 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more. Was this helpful? React with 👍 / 👎 | Gitar |
Promote dev to master and cut 1.0.0-beta.6.
Headline: one Browser app with a Neko-attach toggle (the separate streamed-browser app is gone), a RAM-capable Pi host can serve sessions itself, and
taos rollbackfor recovering a broken update from the CLI.120 commits since beta.5. Full notes in CHANGELOG.md under [1.0.0-beta.6].
Added
taos rollbackrecovery path (restores previous branch + version).Changed
Fixed