github craft-ai-agents/craft-agents-oss v0.9.3

2 hours ago

v0.9.3 — Mobile/compact UI rework, Manifest provider preset, oversized-tool-result poisoning fix, Telegram auto-reconnect

Features

  • Mobile-first compact mode — Renderer reworked so the same Electron React tree adapts cleanly to narrow viewports. Primarily targeting the WebUI delivery, but also lights up automatically in the desktop app whenever the shell is resized below 768px wide. Highlights: (a) isAutoCompact derived from @container/shell width — single-panel iOS-style drill-in between the navigator (session list / sources / etc.) and the focused content panel; sidebar + right rail auto-hide; layout runs flush to the viewport edges. (b) Mobile-first AppMenu with a full-screen nav stack (MobileAppMenu) extracted from the existing component; desktop branch (DesktopAppMenu) keeps the previous behaviour verbatim. (c) Touch-first pickers — workspace switcher, source picker, permission-mode selector, and session-list filter all swap from Radix popovers to vaul Drawer bottom sheets in compact mode (Radix portals out of the panel container query, so popovers were getting clipped on narrow viewports). (d) Top bar reorganised — workspace pill on the left, action chips collapse, + new chat FAB pins to the viewport bottom (portalled out of the navigator transform so position: fixed resolves to the viewport, not the transformed ancestor). Existing CSS uses container queries throughout, so the desktop layout (≥768px shell) is structurally unchanged. PR #363. (83cc0cca, 3a63cbe1, 1640b181, 90e75c7b, e6e3247a, e24d4062, 7f2627ab)

  • Manifest as a default API-key provider preset — Adds Manifest (OpenAI-compatible endpoint at https://app.manifest.build/v1) to the API-key provider presets alongside HuggingFace, Vercel AI Gateway, and the other OpenAI-compat options. Routes through the same path as the custom preset (pins customEndpoint.api='openai-completions', skips Pi model discovery, resolves piAuthProvider='openai'); a new OPENAI_COMPAT_CUSTOM_URL_PRESETS set captures this category so future non-Pi-SDK OpenAI-compat providers can be added with a single entry. Default model field is seeded with auto to match Manifest's routing model — and handleBaseUrlChange now seeds the same default when the user types a manifest.build URL directly (previously only the click path seeded the model). Connection list shows "Manifest" name + Manifest favicon + branded subtitle. External contributor: @guillaumegay13 — originally lukilabs/craft-agents-oss#731, lifted via PR #367 with two follow-up review fixes folded in. (e16d28f1, c627480d, 4db12f08)

Improvements

  • GHCR + workflow rename: lukilabscraft-ai-agents — Cuts the GitHub Container Registry image namespace and all workflow/script references over to the new GitHub org. Marketing site GitHub links also updated. No user-visible config change for app users; impacts anyone pulling docker images or referencing the OSS sync scripts. (8ee72a47, 99dd5e35, f040d555)

  • Repo-wide i18n string-scan lint — New lint:i18n:strings script scans the entire repo for hardcoded English strings that should go through i18n; lint-i18n-staged.sh was trimmed in the same commit since the per-file scan is now subsumed by the repo-wide one. Helps prevent future strings from skipping the i18n pipeline. (013674e0)

  • Settings icons consistency cleanupSettingsIcons.tsx collapsed by ~180 lines to share one icon style across settings sections; small models-pi.ts touch-up alongside. Contributed by Balint Orosz. (da685016)

  • Messaging access channel routing — 9 messaging access-control channels (messaging:access:{getOwners,setOwners,getMode,setMode,getPending,dismissPending,allowPending,setBindingAccess} + messaging:pendingChanged) added to REMOTE_ELIGIBLE_CHANNELS. They were declared in channels.ts during the recent Telegram permission-buttons / access-control work but never registered in routing.ts — the exhaustiveness test was failing on this branch base. (9b694d8d)

Bug Fixes

  • Session poisoning from oversized tool results — A single Read of a base64-heavy file could push a session past the model's context window, after which every retry returned invalid_request and the only "fix" was abandoning the session. Two compounding bugs fixed: (a) The chars/4 token estimator under-counts dense base64 by ~25%, so the existing 15K-token spill threshold fired too late; new estimateTokensDensityAware() switches to chars/1.5 when ≥70% of a ≥20KB tool result is inside unbroken base64-charset runs (≥100 chars), and TOKEN_LIMIT is lowered to 12000 for additional headroom. (b) The invalid_request UX actively misled users — the hardcoded fallback advice ("Try removing any attachments / check if images are in supported format") fired regardless of what was sent or what the API said, because both real-error sources are dead on the Claude SDK path (parseApiErrorFromDebugLog reads a file the SDK no longer writes; the network interceptor is Pi-only). Now: split overloaded ONE_M_CONTEXT_HINTS into 1M-tier-specific (context-1m/tier) and generic context-overflow (context window/prompt is too long/…); generic overflows route to a new "Context Window Exceeded" error with /compact + new-session advice; "remove attachments" hints only fire when the API message actually mentions image/attachment/media/format or the just-sent user turn included attachments (new userTurnHadAttachments field threaded through ClaudeSdkErrorContext); when neither error source provides detail, append a pointer to ~/Library/Logs/@craft-agent/electron/main.log. PR #365. (636b0b67, fad9cbb3)

  • Telegram polling auto-reconnect after failure — When Telegram polling stopped (most commonly a 409 Conflict from two app instances sharing the same bot token), connected stayed false permanently and every subsequent session event routed via telegramTopic automations was silently dropped — bindings were created, sessions ran, responses were generated, but nothing ever reached Telegram. TelegramAdapter now calls scheduleReconnect() on any polling failure with exponential backoff: 30s base for 409 (gives the competing process time to exit), 5s for other errors, capped at 5 min. destroy() cancels any pending timer so intentional shutdowns don't re-enter the loop. MessagingGateway.onSessionEvent also now logs a warn (adapter_not_connected) instead of silently continuing, so future disconnects surface immediately in messaging-gateway.log. PR #366. (28f1082d)

  • WhatsApp voice messages / audio attachments now delivered — WhatsApp worker was silently dropping audio attachments instead of forwarding them to sessions. The worker now emits audio/media attachments correctly. Closes #719. (84d6d0fd)

  • source_test forwards OAuth/bearer tokens to the MCP probe — Connection probe was reporting invalid_token for OAuth MCP sources whose live runtime succeeded with the same source — source_test wasn't passing the access token to the probe. Fixed: the access token is now forwarded so the probe matches live-runtime auth. Closes #720. (0dd6eeef)

  • Telegram permission buttons idempotent + clear keyboard on resolution — Permission buttons could double-fire on rapid taps; the inline keyboard also persisted after the permission was resolved. Buttons are now idempotent and the keyboard is cleared once the permission is granted/denied. Closes #726. (9340b2b5)

  • Model picker exposes connection switcher on empty session for single-model pi_compat default — When a workspace's default connection was a pi_compat connection with only one model, the model picker hid the connection switcher entirely, making it impossible to switch providers from an empty session. The picker now exposes the connection switcher even in this case. Closes #727. (7faf9fc4)

  • Windows build: sparse-checkout cone mode + illegal-character filename rename — Two issues blocking Windows CI: (a) sparse-checkout was using non-cone mode, which doesn't apply on Windows; switched to cone mode. (b) Hermes - Anna: thinking.pdf from the project-evolution archive contained :, illegal on Windows; renamed. Project-evolution PDFs are also excluded from the Windows checkout entirely. (5cc83b86, bf187448, 28741005)

  • Compact-mode polish (multi-commit) — A series of small fixes uncovered during compact-mode bring-up: React #300 (Maximum update depth) when toggling isCompact on resize (227f3486); new-chat FAB pins to viewport bottom via portal so position: fixed resolves correctly, and is hidden when a chat is open (406ece09, 3ce4ffb3); PanelHeader title centered across full panel width (7d81e6a7); polish on toggles + topbar sizing for narrow viewports (060ae0d1); compact mobile header controls polish (74c52244).

  • AppMenu: drop history bridge + Keyboard Shortcuts row in compact — The menu had a history bridge that rolled back menu navigations on back-button press; removed (390d4eeb). The Keyboard Shortcuts row was also dropped from the mobile menu since it's irrelevant on touch (b38b1c05).

  • Docs: correct path to Mid-stream sends setting — Documentation referenced an outdated path. Fixed. (97f58dec)

Breaking Changes

  • None. All changes are backward-compatible. NEW DOCKER IMAGE -> ghcr.io/craft-ai-agents/craft-agents-server

Notes

  • External contributors in this release:

  • Repo namespace migration: GHCR images and workflow references moved from lukilabscraft-ai-agents. If you pull ghcr.io/lukilabs/craft-agents-server, switch to ghcr.io/craft-ai-agents/craft-agents-server. The OSS issue tracker stays at lukilabs/craft-agents-oss (issues #719, #720, #726, #727 linked above).

  • Mobile/compact mode: triggers automatically when the shell width drops below 768px, regardless of whether you're in the desktop app or WebUI. Resize a desktop window narrower to try it.

  • Token-estimator change: the new density-aware spill threshold should keep most context-window crashes from happening in the first place. If you previously saw invalid_request: remove attachments after a Read of a binary-heavy file without an actual attachment, that error is gone — context overflows now route to a separate "Context Window Exceeded" error pointing to /compact.

Don't miss a new craft-agents-oss release

NewReleases is sending notifications on new releases.