Skip to content

release: 1.0.0-beta.6#1288

Merged
jaylfc merged 122 commits into
masterfrom
release/beta-6
Jun 21, 2026
Merged

release: 1.0.0-beta.6#1288
jaylfc merged 122 commits into
masterfrom
release/beta-6

Conversation

@jaylfc

@jaylfc jaylfc commented Jun 21, 2026

Copy link
Copy Markdown
Owner

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 rollback for recovering a broken update from the CLI.

120 commits since beta.5. Full notes in CHANGELOG.md under [1.0.0-beta.6].

Added

  • Coding Studio model-agnostic tool-calling loop over workspace-jailed fs tools (LiteLLM-backed).
  • Cluster capability map from registration/heartbeat + admin endpoints + non-destructive stale-node sweep.
  • Append-only board audit log + project-scoped activity feed + task audit endpoint.
  • taos rollback recovery path (restores previous branch + version).

Changed

  • One Browser app (Neko attach via toggle; host-capable Pi serves sessions).
  • De-seed X/Reddit/YouTube/GitHub from the default store (optional installs).

Fixed

  • Browser session resolves worker before creating the session row (no orphans).
  • Auto-expiring toasts no longer archive into History.
  • Dependabot majors: actions/checkout v7, fetch-metadata v3, python deps.

jaylfc added 30 commits June 20, 2026 23:20
…-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.
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
jaylfc added 17 commits June 21, 2026 11:24
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)
… conflict)

#1279 and #1282 both appended to test_routes_cluster_capability.py; keep both
the registration tests and the stale-offline sweep test.
…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-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions

Copy link
Copy Markdown

👋 Thanks for the PR! This one targets master, which is our
stable branch (it's what live installs track). Please retarget it to
dev — click Edit next to the PR title and change the base
branch dropdown from master to dev. Your commits and any review
carry over, nothing is lost.

See CONTRIBUTING.md for the branch model.

@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jaylfc, we couldn't start this review because you've reached your PR review rate limit.

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 @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

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 configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2eddeb63-43bf-4500-b338-74e0d8804acb

📥 Commits

Reviewing files that changed from the base of the PR and between 5c98863 and d2ae670.

⛔ Files ignored due to path filters (5)
  • desktop/package-lock.json is excluded by !**/package-lock.json
  • neko-lan-test.png is excluded by !**/*.png
  • neko-single-test.png is excluded by !**/*.png
  • neko-tcpmux-test.png is excluded by !**/*.png
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (85)
  • .github/workflows/build-neko-rk3588-image.yml
  • .github/workflows/dependabot-automerge.yml
  • .gitignore
  • CHANGELOG.md
  • app-catalog/streaming/neko-browser/Dockerfile.rk3588
  • desktop/package.json
  • desktop/src/apps/CalendarApp.test.tsx
  • desktop/src/apps/StreamedBrowserApp/StreamedBrowserApp.test.tsx
  • desktop/src/apps/StreamedBrowserApp/StreamedBrowserApp.tsx
  • desktop/src/apps/StreamedBrowserApp/index.ts
  • desktop/src/components/AppErrorBoundary.test.tsx
  • desktop/src/components/ContextMenu.test.tsx
  • desktop/src/components/Dock.test.tsx
  • desktop/src/components/EmojiPicker.test.tsx
  • desktop/src/components/Launchpad.test.tsx
  • desktop/src/components/LoginScreen.test.tsx
  • desktop/src/components/NotificationCentre.test.tsx
  • desktop/src/components/NotificationCentre.tsx
  • desktop/src/components/NotificationToast.test.tsx
  • desktop/src/components/NotificationToast.tsx
  • desktop/src/components/ServiceIcon.test.tsx
  • desktop/src/components/SetupChecklist.test.tsx
  • desktop/src/components/StatusIndicators.test.tsx
  • desktop/src/components/TaosAssistantSettings.test.tsx
  • desktop/src/components/TopBar.tsx
  • desktop/src/components/UpdateAvailableToast.test.tsx
  • desktop/src/components/WallpaperPicker.test.tsx
  • desktop/src/hooks/use-installed-optional-apps.test.ts
  • desktop/src/hooks/use-installed-services.test.ts
  • desktop/src/hooks/use-installed-userspace-apps.test.ts
  • desktop/src/hooks/use-shortcut-registry.test.tsx
  • desktop/src/hooks/use-snap-zones.test.ts
  • desktop/src/registry/app-registry.ts
  • desktop/src/registry/optional-apps.ts
  • desktop/src/stores/dock-store.test.ts
  • desktop/src/stores/notification-store.test.ts
  • desktop/src/stores/notification-store.ts
  • desktop/src/stores/theme-store.test.ts
  • desktop/vite.config.ts
  • docs/STATUS.md
  • pyproject.toml
  • scripts/rollback.sh
  • tests/conftest.py
  • tests/test_agent_registry_store.py
  • tests/test_apps_installed.py
  • tests/test_board_audit.py
  • tests/test_board_audit_wiring.py
  • tests/test_browser_container.py
  • tests/test_browser_proxy_origin.py
  • tests/test_capability_map.py
  • tests/test_coding_loop.py
  • tests/test_coding_model.py
  • tests/test_coding_tool_loop.py
  • tests/test_download_manager.py
  • tests/test_feedback_store.py
  • tests/test_fs_tools.py
  • tests/test_installed_apps.py
  • tests/test_office_docs.py
  • tests/test_rollback.py
  • tests/test_routes_agent_deploy.py
  • tests/test_routes_apps.py
  • tests/test_routes_browser_sessions.py
  • tests/test_routes_cluster_capability.py
  • tests/test_routes_taos_agent.py
  • tests/test_torrent_settings.py
  • tinyagentos/__init__.py
  • tinyagentos/agent_tools/__init__.py
  • tinyagentos/agent_tools/coding_loop.py
  • tinyagentos/agent_tools/coding_model.py
  • tinyagentos/agent_tools/coding_tools.py
  • tinyagentos/agent_tools/fs_tools.py
  • tinyagentos/app.py
  • tinyagentos/board_audit.py
  • tinyagentos/cluster/capability_map.py
  • tinyagentos/projects/task_store.py
  • tinyagentos/rollback.py
  • tinyagentos/routes/__init__.py
  • tinyagentos/routes/apps.py
  • tinyagentos/routes/browser_sessions.py
  • tinyagentos/routes/cluster.py
  • tinyagentos/routes/cluster_capability.py
  • tinyagentos/routes/coding.py
  • tinyagentos/routes/projects.py
  • tinyagentos/update_runner.py
  • tinyagentos/worker/browser_container.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/beta-6

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…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
Comment on lines 68 to 79
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) };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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 👍 / 👎

Comment on lines 137 to +151
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
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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 👍 / 👎

Comment on lines +120 to +128
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
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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 👍 / 👎

@gitar-bot

gitar-bot Bot commented Jun 21, 2026

Copy link
Copy Markdown

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.
Learn more about usage limits

Code Review 👍 Approved with suggestions 0 resolved / 3 findings

Promotes 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 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.

💡 Edge Case: Failed browser session start leaves an orphaned session row

📄 tinyagentos/routes/browser_sessions.py:137-151

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.

💡 Edge Case: parse_completion may KeyError on tool-call without 'arguments'

📄 tinyagentos/agent_tools/coding_model.py:120-128

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 {}.

🤖 Prompt for agents
Code Review: Promotes 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.

1. 💡 Edge Case: Archived notifications can be silently evicted by the 100-item cap
   Files: desktop/src/stores/notification-store.ts:68-79

   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.

2. 💡 Edge Case: Failed browser session start leaves an orphaned session row
   Files: tinyagentos/routes/browser_sessions.py:137-151

   `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.

3. 💡 Edge Case: parse_completion may KeyError on tool-call without 'arguments'
   Files: tinyagentos/agent_tools/coding_model.py:120-128

   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 `{}`.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

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

@jaylfc jaylfc merged commit 79869ca into master Jun 21, 2026
8 of 9 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in TinyAgentOS Roadmap Jun 21, 2026
@jaylfc jaylfc deleted the release/beta-6 branch June 21, 2026 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant