Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Releases: craft-ai-agents/craft-agents-oss

v0.10.3

09 Jun 23:32
@rjulius23 rjulius23

Choose a tag to compare

v0.10.3 — Claude Fable 5

Features

  • Claude Fable 5 is here — Anthropic's most capable widely released model (GA 2026年06月09日) is now available in Craft Agent on the Claude Agent SDK path, with a full 1M-token context window. It works across direct Anthropic connections and AWS Bedrock (us/eu/global inference-profile variants), with the model description localized in all 7 languages. Opus 4.8 remains the default — Fable is offered alongside it, not in front of it — and it is added to the Pi → Anthropic auth-bridge preferences below Opus. Because Fable 5 (and the Mythos 5 class) run with adaptive thinking always on and reject an explicit disabled thinking option, the thinking resolver now maps the "off" and minimize-thinking cases to low-effort adaptive thinking for these models; Opus, Sonnet, and Haiku behavior is byte-for-byte unchanged. (22c7ae99)

Improvements

  • Claude Agent SDK uplifted to 0.3.170@anthropic-ai/claude-agent-sdk moves from 0.3.154 → 0.3.170 (root plus the core and shared peer dependencies, lockfile refreshed). No API breakage; the full typecheck passes clean. (22c7ae99)

Bug Fixes

  • None.

Breaking Changes

  • None.
Assets 5
Loading
ninjaeon, lin72h, pynickle, Loncakovandrej789, and xuzhixiangya reacted with thumbs up emoji
5 people reacted

v0.10.2

09 Jun 11:17
@rjulius23 rjulius23

Choose a tag to compare

v0.10.2 — Link labels, Anthropic account visibility, and prompt-cache fixes

Features

  • Link label value type — Labels can now carry a link value alongside the existing string/number/date types. A link value renders as a clickable chip (the URL scheme is stripped for display) that opens in your external browser, with a keyboard-accessible "Open link" action in the value popover. The type is threaded through the zod schema, CLI, and agent-prompt layers, and the clickable value appears consistently in the session list, chat display, and chat-input badges. Documented in labels.md with validate/format/resolve tests. (8aae50ad)

  • Resolved Anthropic account & org shown per OAuth connection — Settings → LLM Connections now displays the real Anthropic identity ("email · org") each Claude OAuth grant resolves to, captured from the token-exchange response and persisted on the connection. When two connections in the same workspace resolve to the same Anthropic account (shared quota — a previously invisible mis-route), an amber warning is surfaced. This also fixes a load-bearing bug where updateLlmConnection rebuilt connections from a hardcoded field allowlist and silently dropped any unlisted field on every save; the identity fields are now preserved with a round-trip test. Fixes #838. (a4b8868e)

  • Last sent message restored to the input on Stop — Clicking Stop (an explicit cancel, not a redirect or new send) now copies your last sent message back into the chat input so you can tweak and resend it. It is append-safe: a draft typed while the agent was running is preserved, and the restored text is appended below it. Queued, never-sent messages continue to be handled by the existing restore path. (cfbe802b)

Improvements

  • None.

Bug Fixes

  • Pi prompt-cache no longer busts every turn — The Pi adapter folded volatile context (minute-precision date/time, session_state, source state) into the system prompt, which pi-ai caches as the prefix ahead of all history — so re-stamping it each turn dropped cacheRead to 0 every turn (notably with non-Claude models such as DeepSeek V4). PromptBuilder.buildContextParts is now split into buildVolatileContextParts + buildStableContextParts; the Pi path keeps only stable blocks (workspace capabilities, working directory) in the cached prefix and routes volatile blocks to the user-message tail, mirroring what the Claude path already did. The Claude path stays byte-identical. Fixes #862. (80b478e3)

  • Accept-Plan chevron rotates when the dropdown opens — Both Accept-Plan triggers render via Radix asChild, so data-state="open" landed on the host <button>, never on the nested chevron <svg> — the self-scoped data-[state=open]:rotate-180 never fired. The rotation is now scoped to a named group on the button (group/accept + group-data-[state=open]/accept:rotate-180). Fixes #840. (f97f483b)

Breaking Changes

  • None.
Loading
ninjaeon and Loncakovandrej789 reacted with rocket emoji
2 people reacted

v0.10.1

02 Jun 13:45
@rjulius23 rjulius23

Choose a tag to compare

v0.10.1 — Claude Opus 4.8 default, localized session titles, and Apple Silicon–only macOS builds

Features

  • None.

Improvements

  • Claude Opus 4.8 is now the default Opus model — Upgraded the Claude Agent SDK to 0.3.154 and set Claude Opus 4.8 as the default Anthropic Opus model, while keeping Opus 4.7 selectable. The deprecated Opus 4.6 is removed from the model pickers. Existing direct-Anthropic Opus 4.7 defaults move to Opus 4.8, and Opus 4.5/4.6 selections migrate to the best available current Opus model. Bedrock mappings, Pi fallback handling, model-migration tests, docs, and UI examples were updated to match. (0a1357b2)

Bug Fixes

  • Session titles honour the Settings → Appearance language — The main-process i18n instance has no language-detection plugin (there is no localStorage in Node) and was never re-hydrated from disk, so it always sat at the en fallback after restart. Title generation (generateTitle / refreshTitle) and the system prompt's "Preferred language" line read that main-process language, so they came back in English even when Appearance was set to another language. The chosen UI language is now persisted to an internal, validated uiLanguage field and the main-process i18n is hydrated from it on startup; the renderer also pushes its resolved language to main once on upgrade so the value is learned without re-picking. Partially addresses #815 and #738. (4a743ef2)

  • Text-selection highlight stays aligned when scrolling a preview — Selecting text inside a scrollable markdown-preview block (the max-h-[400px] overflow-auto wrapper) and adding a follow-up left the yellow range highlight and its numbered chip anchored to the original coordinates, so they drifted away from the text as the block scrolled. A capture-phase scroll listener now recomputes the overlay geometry on any nested scroll — a coords-only fast path coalesced with requestAnimationFrame, with a no-op short-circuit when there are no annotations — keeping the highlight pinned to its text. The same fix is mirrored in the viewer's annotation path. (14bba50c)

Breaking Changes

  • macOS Intel (x64) builds discontinued — Apple Silicon only — Craft Agents for macOS now ships an Apple Silicon (arm64) build only; Intel-based Macs are no longer supported. The x64 .dmg is no longer produced (v0.10.0 was the last release with an Intel build). Apple Silicon (M-series) Macs, Windows, and Linux are unaffected.

  • Legacy language preference field removed — The free-text, user-editable language field in preferences.json is replaced by an internal, validated uiLanguage field driven by Settings → Appearance. Existing config files are tolerated (the schema is passthrough) and the stale language key is scrubbed on read, so no user action is required. The update_user_preferences tool no longer accepts a language argument.

Loading
ninjaeon and lin72h reacted with heart emoji
2 people reacted

v0.10.0

26 May 14:08
@rjulius23 rjulius23

Choose a tag to compare

v0.10.0 — Remote browser_tool bridging, per-workspace browser tab isolation, and #824 basic-auth fix

Features

  • Remote browser_tool bridged into the user's local Electron browser — Agents running on a remote workspace (headless server, docker, WebUI) can now drive the user's local desktop BrowserPaneManager end-to-end. Adds a client:browser:invoke WS capability (advertised on handshake, server invokes client, plain Error with .code preserved through both directions), mirroring how shell.openExternal already works for OPEN_URL. Transport gains hasClientCapability / findClientsWithCapability for routing; Electron gets a new __browser:invoke IPC dispatcher with per-method owner-key authorization, no-manual-window-reuse for remote callers, session-scoped listInstances, and screenshot BufferUint8Array conversion across the wire. server-core gets a RemoteBrowserPaneManager (session-bound IBPM impl) and SessionManager.getBrowserPaneManagerForSession with capability-aware host-client fallback and per-session pin cleanup on disconnect. uploadFile is blocked over the bridge; evaluate is gated by a local allowRemoteEvaluate setting. The Pi runtime learns friendly error mappings for BROWSER_NO_CAPABLE_CLIENT, CAPABILITY_UNAVAILABLE, CLIENT_DISCONNECTED, CLIENT_REQUEST_TIMEOUT, BROWSER_INSTANCE_NOT_OWNED, BROWSER_REMOTE_UPLOAD_NOT_SUPPORTED, and BROWSER_REMOTE_EVALUATE_BLOCKED, and now mirrors Claude's getBrowserToolEnabled gate so Pi no longer advertises browser_tool when the toggle is off. 27 new tests cover wire packaging, per-method authz, capability introspection, host-client fallback, screenshot round-trip, error-code preservation, and the Pi error-mapping contract. (1d926c33)

  • Browser tabs isolated per workspaceBrowserPaneManager is process-global and STATE_CHANGED used to broadcast { to: 'all' }, so a chat in workspace A saw browser tabs and status banners owned by sessions in workspace B. Every BrowserInstance (and the BrowserInstanceInfo DTO) now carries a nullable workspaceId; STATE_CHANGED routes to { to: 'workspace', workspaceId } when set (falling back to { to: 'all' } for unbound manual windows); the browserPane.LIST handler filters by ctx.workspaceId; and the renderer reads a new browserInstancesForWorkspaceAtomFamily keyed by activeWorkspaceId. Windows still run in parallel as real BrowserWindows — this is a UI visibility filter, not a sandbox. REMOVED / INTERACTED stay broadcast-to-all (id-only payloads, harmless no-op on workspaces that never saw the entry). workspaceId ships optional on the DTO, so old renderers tolerate missing values (treats undefined as null → passes the filter, equivalent to today's behavior). 17 new tests across atom filter, BPM stamping, and broadcast/LIST routing. (af817192)

Improvements

  • markdown-preview block documented in the rich-output reference — The markdown-preview block (shipped in v0.9.6) is now covered in apps/online-docs/go-further/rich-output.mdx alongside the existing html-preview / pdf-preview / image-preview entries, so users discovering the block in-chat can find usage examples and the src / items field reference in the docs. (2d9693b1, 70c2955f)

  • Browser-bridge wiring is observable from server logs — Three sessionLog.info lines in SessionManager now confirm whether setRpcServer ran at bootstrap and whether the browser-pane-forwarding block executed at agent init. Makes it possible to diagnose remote workspaces that still hit "Browser window controls are not available" from server logs alone, without attaching a debugger. (ad26e61d)

Bug Fixes

  • Renderer accepts both local AND remote workspace ids when filtering tabs — When connected to a remote workspace, a renderer has two relevant workspace ids: activeWorkspaceId (the LOCAL Craft Agents window's identity, used for locally-opened manual tabs) and activeWorkspace.remoteServer.remoteWorkspaceId (the REMOTE server's id, used by the remote agent when it stamps tabs through the WS bridge). The first iteration of the workspace-isolation filter only matched activeWorkspaceId, so tabs stamped with the remote id (which is what every remote agent-opened browser carries) got filtered out — the TopBar tab strip and the toolbar status badge became invisible for remote browsers, and opening one then hiding it left it inaccessible. Replaced the atomFamily with a plain helper filterInstancesForWorkspace(local, remote): tabs match if either id matches (or if workspaceId is null/undefined for back-compat). (bf8429fa)

  • STATE_CHANGED broadcasts to all clients again; the visibility filter lives in the renderer — The Phase-4 server-side workspace filter (on both STATE_CHANGED routing and the LIST handler) was wrong for remote-mirror workspaces: a renderer's transport-level workspaceId is the LOCAL window's identity, while remote-bridged browser tabs carry the REMOTE server's workspace id. The two never match, so STATE_CHANGED targeted at the remote id got dropped by the WS routing layer (no local renderer reports itself as being in the remote workspace) and LIST returned empty for the same reason. Workspace isolation now lives entirely in the renderer (filterInstancesForWorkspace), which knows both ids via activeWorkspace.remoteServer.remoteWorkspaceId. The handler reverts to { to: 'all' } broadcasts and a full LIST response. Privacy is unchanged — every locally-connected renderer belongs to the same user — and remote tabs finally show up in the TopBar of the workspace that owns them. (f831bb42)

  • No window reuse on the remote-bridge lifecycle path (closes the cross-workspace hijack) — The capability dispatcher correctly set allowReuseManual=false for createForSession but flowed getOrCreateForSession and focusBoundForSession through the public helpers, which default allowReuseManual=true. The remote agent's browser_tool open maps to focusBoundForSession, so it could adopt an unbound window left behind by a local session — exactly the cross-workspace hijack the workspaceId filter was meant to block. The workspaceId filter still helps but it's best-effort: windows created before workspace stamping (or via paths that never set workspaceId) have workspaceId=null and remain universally adoptable. Belt-and-brace fix: every remote lifecycle call now passes allowReuseManual=false, so remote sessions always create fresh windows unless they already own one. (ce3340a1)

  • Unbound-window reuse scoped to the owning workspace (no more "tab moved from workspace A to B") — When a session's turn ends, unbindAllForSession() clears boundSessionId and flips ownerType to 'manual' so the next turn of the same session can re-bind the window; the workspaceId stamped at creation is preserved. findReusableUnboundInstance() was matching ANY unbound 'manual' window regardless of workspace, so a session in workspace B would happily pick up the leftover window from workspace A — bindSession() would then overwrite workspaceId to B, effectively "moving" the window from A to B and making workspace A's tab strip lose the entry while B's gained it. Reuse is now allowed only when the candidate's workspaceId is null (truly user-opened manual window — adoptable by anyone) or matches the caller's workspaceId. Same-workspace next-turn reuse still works. (ceb24603)

  • TopBar-opened manual windows inherit the workspace they were opened in — The browserPane.CREATE handler created manual windows with workspaceId defaulting to null, which the workspace-isolation filter intentionally treats as "visible to all workspaces" — so a TopBar-opened tab leaked into every workspace's tab strip. The renderer that fires CREATE always has ctx.workspaceId set, so the handler now passes it through to createInstance / createForSession. CLI / agent-harness callers with no workspace context (ctx.workspaceId === null) still get the broadcast-to-all behavior as a safe fallback. (7dfcaeac)

  • BrowserInstance projected to a plain snapshot before IPC return — The local BrowserPaneManager.getInstance(id) returns the live BrowserInstance which embeds Electron native references (window: BrowserWindow, pageView: BrowserView, ...). When the __browser:invoke dispatcher returned that object over IPC, Electron's structured-clone serializer threw An object could not be cloned and the remote agent's logging-side getInstanceAsync call failed. Added toSnapshot(instance) that emits only the IBPM-declared fields (ownerType, ownerSessionId, isVisible, title, currentUrl) and routed the dispatcher's getInstance branch through it. (8e2534b5)

  • source_test base64-encodes basic-auth credentialstestApiConnectionWithAuth was interpolating the raw vault value into the Authorization header, so basic-auth sources got Basic {"username":"...","password":"..."} and 401'd against every provider. The vault stores source_basic credentials as JSON (written by source_credential_prompt / the WebUI); the runtime path in api-tools.ts buildHeaders already parses and base64-encodes — the validator path was just left out. Now parses the token as JSON when it has username+password; falls through to pass-through behavior for legacy / hand-edited base64 entries and any non-JSON string, mirroring buildHeaders(). Three regression tests cover the JSON form, the legacy already-encoded form, and a non-JSON garbage token. Fixes #824. (96dd7c0d)

Breaking Changes

  • None. The workspaceId field on the BrowserInstanceInfo DTO is optional, so older renderers and older agents tolerate missing values (treats undefined as null → passes the visibility filter, equivalent to pre-0.10.0 behavior).
Loading

v0.9.6

25 May 00:47
@rjulius23 rjulius23

Choose a tag to compare

v0.9.6 — Auto-update window restoration, mid-session credential refresh, and #807/#798/#804 fixes

Features

  • Workspace name in window title when multiple windows are open — With one window open the title stays as the app name ("Craft Agents"). Open a second window and each window's title becomes the workspace name it belongs to, so windows are trivial to tell apart in Cmd-Tab, Mission Control, and the Windows taskbar. The renderer's static <title> is suppressed so it can't clobber the main-process title. (5a49b6ca)

  • Inline markdown-preview block for rendering .md files — A new markdown-preview code-block type mirrors html-preview / pdf-preview / image-preview: reference a .md file by absolute path and the chat renders it through the shared Markdown component, with a disablePreviewBlocks guard that prevents markdown-preview-inside-markdown-preview recursion without disabling other nested preview blocks. Registered in both minimal (assistant chat) and full modes; supports multi-item items arrays. Partially addresses #807. (45760a6f)

Improvements

  • Online-docs coverage for multi-window titles and auto-update restorationapps/online-docs/go-further/workspaces.mdx now documents the new window-title behavior and the auto-update window-state preservation, so users discovering these features in-app can find rationale and edge-case notes in the docs. (755a8b77)

  • Online docs introduction polish — Tightened wording in the getting-started introduction (Mintlify dashboard edit). (3a5378db)

  • Messaging gateway docs reflect the 0.9.5 fallback fix — Clarifies that progress and final_only modes now both fall back to the most recent assistant text when a run ends on a tool call without a non-intermediate text_complete, instead of leaving a thinking bubble (progress) or staying silent (final_only). Genuinely empty runs are still silent. (0cfd1ffb)

Bug Fixes

  • Multi-window state survives auto-update — electron-updater (Squirrel.Mac) destroys all BrowserWindows between quitAndInstall and before-quit firing, so the existing window-state save ran with an empty snapshot and clobbered ~/.craft-agent/window-state.json with { windows: [] }. Users lost their multi-window setup every time they accepted an update. installUpdate now fires a setBeforeUpdateQuitHook callback that captures and saves window state while windows still exist, and the late before-quit path adds an empty-snapshot guard so the pre-update save can't be overwritten. (3db842e0)

  • API source credentials refresh mid-session — Sources with bearer/header/query/basic auth captured the credential as a static string at tool-creation time. After refreshing an expired token via source_credential_prompt, the in-process tool kept sending the stale value (401 until full session restart) even though source_test confirmed the new token worked. Non-OAuth API sources now route through a credential getter that reads the vault on every call, mirroring the existing OAuth / renew-endpoint path. OAuth and renew-endpoint sources are untouched — they already have refresh via TokenRefreshManager. (5b6a0588)

  • Stale source_apikey credential no longer leaks when flipping authType to 'none'SourceCredentialManager.getCredentialId() maps 'none', 'header', and 'query' to the same source_apikey slot. Flipping a source from a credential-bearing authType to 'none' left the stored credential addressable under that slot, where it could later override defaultHeaders on a rebuild — the bare credential value got sent as a Cookie header instead of the new defaultHeaders.Cookie value. saveSourceConfig now best-effort-deletes the source_apikey slot when the new config is an API source with authType:'none'. Cleanup never throws and never blocks the config write. (d0c70f23)

  • Blocked URL schemes now explain why + DOM hrefs are sanitized — When react-markdown's defaultUrlTransform stripped a file: / javascript: URL to empty, the anchor handler fell back to anchor text and new URL(text) rejected it as "Invalid URL" — a generic toast with no rationale. DANGEROUS_SCHEMES is now a Map<scheme, reason>, the reason flows through the OPEN_URL handlers in both server-core and the Electron GUI, and the error message now reads e.g. URL blocked (file:). file: URLs are blocked because shell.openExternal can launch local executables on Windows.... The DOM href attribute is also sanitized through defaultUrlTransform and set to undefined for dangerous schemes, closing the middle-click / cmd-click escape route through Electron's setWindowOpenHandler and will-navigate. Fixes #807 (URL handling part). (746ebb34)

  • cache_control 1h TTL ordering bug and over-broad "tool not supported" classifier — Two bugs surfaced together when extendedPromptCache was enabled on an Anthropic connection at session start. (1) upgradePromptCacheTtl walked system + messages + top-level cache_control but skipped body.tools. Anthropic processes blocks in order tools → system → messages and rejects requests where ttl='1h' appears after ttl='5m', so a stale 5m on any tool produced system.0.cache_control.ttl: a ttl='1h' cache_control block must not come after a ttl='5m' cache_control block. Tools are now walked first in both the upgrade and disabled-strip paths. (2) parseError misclassified the same 400 as "Model Does Not Support Tools" because the heuristic fired on the API's hint string mentioning tools. The overly broad pattern is dropped and a final invalid_request_error / 400 branch routes generic Anthropic 400s to invalid_request instead of unknown_error. (26e6e675)

  • Mobile WebUI send button stays visible when the model name is long — The compact bottom-bar layout had every left-side item as shrink-0 with no overflow guard on the outer row, so a long custom-endpoint model name on a 375 px viewport overflowed the row and pushed the send button off screen. CompactModelSelector's trigger is now shrinkable with a min-w-[64px] tap-target floor, and the compact bottom-bar children are wrapped in their own min-w-0 shrink overflow-hidden group so the model label truncates first and the send button stays anchored to the right. Fixes #798. (5e95e72e)

  • Headless server auto-retries source_activated like the Electron renderer did — The [<slug> activated] re-send moved into SessionManager.processEvent so headless deployments (WebUI, docker server) chain source activations the same way the Electron renderer did. The renderer's auto_retry effect is removed. A 2 s content-match dedup window keyed on a {content, deadlineMs, committed} slot on ManagedSession prevents a double-send during a mixed-version rollout (legacy renderer + new server) — first matching sendMessage (server timer OR legacy RPC) wins and claims the slot, subsequent matches within the window drop. Retry timer + pending slot are cancelled on both session-delete sites (main deleteSession path and the branch-creation rollback path). Fixes #804. Co-authored with Guillaume Gay. (5cb7b8c1)

  • PR 378 review hardening (markdown / Electron URL handling, source-activation auto-retry guards, deterministic stale-credential cleanup) — Follow-up commit addressing review findings on the URL-safety, auto-retry, and credential-cleanup PRs above; also removes a leaking source-test module mock that was hiding the credential-cleanup regression. (42b986e1)

Breaking Changes

  • None. All changes are backward-compatible.
Loading

v0.9.5

19 May 22:16
@rjulius23 rjulius23

Choose a tag to compare

v0.9.5 — Compact-mode UX polish and MCP / branching stability

Features

  • Compact-mode drawer for the session row menu — Session row context menus on compact / mobile layouts now open as a vaul drawer instead of a clipped Radix popover, matching the drawer pattern already used for status, labels, share, and messaging actions. (a0468049)

  • Drawer-based working-directory selector in compact mode — The working-directory picker switches to a drawer on narrow widths so the path list, recent dirs, and "Choose folder..." action remain reachable without horizontal scroll. The desktop dropdown is unchanged. (6e147c03)

  • Expandable chat input on compact layouts — Users can now tap to expand a collapsed chat input on compact / mobile views so longer prompts are easier to compose without leaving the active session. (15fe589b)

  • Drawer-based AcceptPlan picker in compact mode — The plan-acceptance UI uses a drawer in compact / mobile layouts so action rows aren't pushed off-screen on narrow widths. (f8e92a11)

  • Compact model selector in the web UI's mobile / auto-compact view — The web UI's model picker collapses into a compact selector when the shell width crosses the mobile breakpoint, matching the Electron app's container-query behavior. (75c7825d)

Improvements

  • Shared useWorkingDirectoryState hook — Path resolution, recent dirs, and folder-picker handling are extracted into a single hook so the desktop dropdown and compact drawer can't drift in behavior. (aa01895d)

  • Windows RTK install docs — Clarifies the Windows install path in the RTK setup docs so the "RTK not found" detection in Settings → AI → Performance matches what users see on Windows. (129c28ff)

Bug Fixes

  • Branching on the latest turn no longer drops the last assistant message — The Pi-backed branching path now captures the conversation anchor after the SDK appends the new entry, so branching off the most recent turn no longer truncates the message that triggered the branch. Fixes #782. (0988d0d6)

  • Stdio MCP source_test gives real diagnostics instead of a fake timeoutsource_test for stdio MCP servers now runs a single process with a proper stderr-activity watchdog and surfaces actual startup output, replacing the false "Server startup timeout" that fired for any slow-but-healthy server. Fixes #787. (a7fa0a3a, 69d74167)

  • Parallel source_test calls no longer wedge a session — When a source-activation abort interrupts a turn, sibling tool_result blocks are now drained before the abort propagates so the SDK doesn't end up with orphaned tool_use IDs that permanently jam the next turn. Fixes #790. (58087fbf)

  • AcceptPlan dropdown positioning and compact visibility — The desktop AcceptPlan dropdown is now built on Radix DropdownMenu, fixing anchor drift and viewport clipping that could push actions off-screen. The web UI also now actually renders the dropdown in compact / mobile views — previously hidden behind a wider-only branch. (01d062e3, d32f390d)

  • Chat view no longer stuck on "Thinking..." when a turn ends on a tool call — Mirrors the messaging-gateway fix on the Electron main UI side. When the Pi agent emits intermediate text plus a tool call and then completes without a non-intermediate text_complete, groupMessagesByTurn now uses the session's isProcessing=false signal to mark the open turn complete and promote the intermediate text as the response. Pre-fix the chat sat on "Thinking..." forever and the user had to send a follow-up message to unstick it.

  • Messaging gateway delivers the final assistant message in progress / final_only modes — Automations whose last action is a tool call (e.g. the agent uses a tool to send the Telegram message and never emits a clean non-intermediate text_complete) used to leave progress frozen on 💭 thinking... and final_only silent. The renderer now tracks the most recent assistant text regardless of isIntermediate and falls back to it on complete when no clean final arrived; genuinely empty runs still leave the status label in place. Thanks to @nheagy for the original PR (#779). (13187c2c)

  • SDK Agent subagent activity groups are collapsible again — The activity grouping for SDK Agent subagent runs no longer renders flat; the collapse toggle behavior is restored. (774e7ecb)

Breaking Changes

  • None. All changes are backward-compatible.
Loading

v0.9.4

15 May 17:07
@rjulius23 rjulius23

Choose a tag to compare

v0.9.4 — RTK token optimization, compact-session fixes, Codex transport stability

Features

  • Optional RTK Bash token compression — Adds opt-in support for RTK in Settings → AI → Performance. Craft Agent still shows and permission-checks the original Bash command, but when RTK is installed (>=0.23.0) and enabled, the execution path is rewritten through rtk so common development-command output is compressed before it reaches the model. The settings UI now detects missing/outdated installs, offers Get RTK + Re-check actions, and shows saved-token / efficiency stats once RTK has processed commands. (754d254c, a96b8706, 57452664)

Improvements

  • Backend packaging cleanup after Pi consolidation — Removes stale Copilot/Codex binary packaging entries, import guards, runtime fields, and docblocks that survived the move to the actual two-backend architecture (ClaudeAgent + PiAgent). This trims dead build metadata and makes the codebase less misleading for future backend work. (a96b8706)

  • OSS README metadata refresh — Adds the Trendshift badge to the OSS README so repository discovery metadata stays current. (7feae925)

Bug Fixes

  • OpenAI/Codex long-running session instability — Upgrades the Pi SDK stack to 0.73.1, picking up the upstream Codex transport fixes: WebSocket setup can fall back to SSE before streaming starts, and cached WebSocket sessions are closed properly during session shutdown. This targets the 1011 keepalive timeout, 1006 disconnect, and certificate-verification failures reported for long-running ChatGPT Plus / Codex OAuth sessions. Fixes #747. (e30762b6)

  • Compact session menu no longer clips nested actions — On narrow/compact layouts, the chat title menu now uses a vaul drawer with iOS-style drill-in panes for Status, Labels, Share, and Messaging instead of Radix nested dropdowns anchored inside the container-query panel. This keeps status and label actions reachable on small widths while leaving the desktop dropdown unchanged. The follow-up review fixes close leaked desktop dropdown state when switching layouts and prevent drawer actions from retargeting if navigation changes the active session while the drawer is open. (db9f506f, 084547e8)

  • Rapid session-label toggles are race-safe — Extracts shared session-menu behavior into useSessionMenuActions and moves label toggling to optimistic state that compounds rapid taps, avoids Strict Mode double side effects, and resets correctly when switching sessions. This fixes compact drawer multi-label editing and removes behavior drift between desktop and compact session menus. (f0c12ed1, 88f8d733)

  • Skills "Show in Finder" opens the real skill folder — Skills list, skill detail, and skill menu actions now reveal the authoritative skill.path directory instead of constructing a synthetic SKILL.md path, and failures surface via a platform-aware Finder/Explorer toast instead of silently no-oping. Fixes #756. (d44e5691)

Breaking Changes

  • None. All changes are backward-compatible.
Loading

v0.9.3

11 May 13:24
@rjulius23 rjulius23

Choose a tag to compare

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. ...
Read more
Loading
ninjaeon, Dioniska, 2Circle, and bichoanh201698-collab reacted with rocket emoji
4 people reacted

v0.9.2

06 May 21:01
@rjulius23 rjulius23

Choose a tag to compare

v0.9.2 — OAuth refresh ordering, Pi system prompt persistence, cross-machine spawn guard, i18n key restore, source_test/streaming/browser hotfixes

Bug Fixes

  • OAuth tokens silently refresh before agent build — On cold sessions, SessionManager.sendMessage ran getOrCreateAgentbuildServersFromSourcesrefreshOAuthTokensIfNeeded in that order. The first build saw stale tokens, emitted AUTH_REQUIRED, and the wrapper called markSourceNeedsReauth — flipping isAuthenticated=false on disk. The user saw a brief "needs auth" UI flicker before the late refresh restored state. Three coordinated changes: (1) refresh now runs before getOrCreateAgent so its internal cold-session build sees fresh tokens, the old refreshOAuthTokensIfNeeded (refresh + conditional rebuild) is gone, and a single post-refresh build is the only build per send; (2) buildServersFromSources reclassifies AUTH_REQUIREDTOKEN_EXPIRED when the credential is merely expired-but-refreshable and skips markSourceNeedsReauth in that case (prevents flicker if refresh is skipped, e.g. during cooldown); (3) TokenRefreshManager.ensureFreshToken failure branches now mirror markSourceNeedsReauth's disk write to source.config in memory, so isSourceUsable() returns false and the failed source is excluded from intendedSlugs by the post-refresh build. Closes #710. (347820ab)

  • Pi backend silently dropped the Craft system prompt — Pi SDK 0.72.1's session.prompt() wipes agent.state.systemPrompt back to _baseSystemPrompt on every turn (agent-session.js ~L796), so pi-agent-server's direct assignment was silently dropped — taking preferences/notes, <session_state>, <sources>, working directory, and all other Craft-built system-prompt content with it. The Anthropic backend was unaffected because it uses the SDK's append: option, which the Claude SDK appends verbatim. New applySystemPromptOverride() helper stamps all three SDK private fields (state.systemPrompt, _baseSystemPrompt, _rebuildSystemPrompt) so the prompt survives both per-turn resets and tool-change rebuilds. Pattern matches OpenClaw's applySystemPromptOverrideToSession — same SDK, same constraint, validated workaround until upstream exposes a public API. Wired into both call sites that previously did state.systemPrompt = ...: the per-turn prompt handler and the ephemeral queryLlm session. Regression test asserts all three fields are stamped (catches the original single-field regression and any future drop of one of the writes). Closes #648. (13f6e63e)

  • SDK spawn guard against stale branch cwd from cross-machine imports — The SDK's Claude Code native binary not found at ... error is a misleading wrapper around spawn ENOENT, which fires whenever the subprocess cwd is also missing — not just when the binary is missing. Cross-machine session imports preserve branchInfo.sdkCwd from the source machine, so a Send to Workspace recipient hits this error on first chat even though the bundle is fine. A pre-spawn guard now catches stale branchFromSdkCwd in chatImpl() and routes through the same branch-fallback recovery the post-failure path already uses (parent summary injection preserved). A new onBranchForkInvalidated callback persists all four fork fields atomically — fixing a pre-existing bug where onSdkSessionIdCleared only persisted sdkSessionId, leaving stale branch fields on disk to reload on next launch. ENOENT classification was lifted out of the if (isProcessError) gate (it never fired for the SDK wrapper, which is a ReferenceError, not a process-exit error); now it disambiguates binary vs cwd vs unknown causes, surfaces typed sdk_binary_missing / sdk_cwd_missing errors after retry exhaustion, and keeps the 2-second auto-retry for the auto-update bundle-swap window. Helpers extracted to agent/spawn-helpers.ts for unit testing (34 new tests; existing branching suite extended with v2 callback coverage). (12166f4a, e40a3801)

  • source_test lastTestedAt now persists — UI no longer always shows "Never" — The source_test handler wrote an ISO string (new Date().toISOString()); the Zod validator in validators.ts enforces z.number().int().min(0), so the string was silently stripped before persist. A second hidden mismatch compounded it: session-tools-core/src/types.ts declared lastTestedAt?: string while the canonical shared type already used number. Fixed by switching the handler to Date.now() and aligning the local type to number. Storage, validator, and UI (formatRelativeTime) already expected a millisecond timestamp — no other files needed changing. Closes #708. (d4427cac)

  • Assistant response content no longer disappears after completionhandleTextComplete unconditionally overwrote the streaming-accumulated message content with event.text from the SDK completion event. If event.text arrived empty (SDK race condition or intermediate event without text), the message bubble went blank. Now destructures streaming from state and applies a fallback chain in both the update-existing and create-new message paths: event.text || streaming?.content || existingMsg?.content || ''. Closes #709. (d4427cac)

  • Browser toggle now fully disables system prompt section and prerequisite rule — Three independent sub-problems gated by the same getBrowserToolEnabled() toggle that was already wired to session-scoped-tools.ts but nowhere else. (a) System prompt: system.ts unconditionally injected the ## Browser Tools section and its "calls are blocked until you read browser-tools.md" warning regardless of the setting — now gated. (b) Prerequisite matcher too broad: prerequisite-manager.ts used isBrowserToolNameOrAlias() which matched any tool named browser_tool, including external MCP tools like mcp__playwright__browser_tool — narrowed to session-scoped canonical names only ('browser_tool' and 'mcp__session__browser_tool'). (c) Rule always registered: the prerequisite rule was registered even when the feature was disabled, causing external browser tools to be incorrectly blocked — getBrowserToolEnabled() check now makes the rule a no-op when the toggle is off. Closes #711. (d4427cac)

Improvements

  • Spawn-guard defensive cleanup simplified per SOLID/KISS review — Rolled back over-engineering identified after the spawn-ENOENT fix while preserving the load-bearing bits (pre-spawn guard, atomic onBranchForkInvalidated, working ENOENT classification, .app-bundle-aware regex). Inlined pickFirstExistingDirectory and probeEnoentPaths; deleted classifyEnoentCause — the 4-line directory loop and 2-line probe didn't earn their abstraction at single call sites. Collapsed the binary|cwd|unknown trichotomy in the catch block to three plain steps: stale-cwd-with-branch → recovery, first attempt → 2 s retry, retry exhausted → typed error pointed at the more likely cause (removes 5 separate enoentCause branches). Dropped the 5-value reason union on recoverFromStaleBranchFork to a single isPreSpawn boolean — status text was the only differentiator. Promoted lastResolvedCwd / lastResolvedBinaryPath from instance fields to chatImpl-scoped locals (visible to the inner catch via closure) — avoids stale-state risk across chat() invocations. ErrorCode centralized in @craft-agent/core/types via re-export from errors.ts. Net −206 lines, no behavior change; 608 agent tests + 102 server-core tests pass. (e40a3801)

Breaking Changes

  • None. All fixes are backward-compatible.

Notes

  • The OAuth refresh fix changes the order of operations on every send-message — refresh now runs once before any server build instead of after a stale build. If you operate API/MCP sources with custom OAuth flows, the visible behavior change is fewer disk writes per refresh cycle and no transient needs_auth flicker on cold sessions. No config or migration is required.
  • Cross-machine "Send to Workspace" recipients who previously hit Claude Code native binary not found at ... on first chat in an imported session will now succeed silently — the guard reroutes through the existing branch-fallback recovery and persists clean fork metadata for the next launch.
Loading
ninjaeon and FatDoge reacted with rocket emoji
2 people reacted

v0.9.1

05 May 20:40
@rjulius23 rjulius23

Choose a tag to compare

v0.9.1 — Telegram bot whitelisting + access control, mid-stream send modes, scoped image-support toggle

Features

  • Telegram bot whitelisting + access control — Solves "anyone who finds the bot can talk to my Agent". Two-tier access model: (1) workspace owners at the platform level (accessMode: 'open' | 'owner-only'), (2) per-binding access with 'inherit' | 'allow-list' | 'open' modes. The first user who runs /pair in a paired supergroup is auto-seeded as workspace owner. Locking the bot to owner-only in Settings → Messaging → Telegram flips the workspace switch and migrates every legacy 'open' binding to 'inherit' so no public binding is left dangling. A new "Allowed users" collapsible (Users icon) lists owners with remove controls; a "Pending requests" panel surfaces senders the gateway already rejected so the operator can Allow or Allow for this chat (per-row decision, never auto-promotes binding-level rejects to global owner). Inline buttons (bind:/perm:/plan:) run through the same access evaluator as text commands so a non-owner can't tap their way past the gate; bot senders are silent-dropped at the platform layer. The unlock path lives in the platform context menu (next to Reconfigure, only when locked). Composite-key pending-store (platform, userId, reason, bindingId) keeps a sender's workspace-level reject separate from their per-binding rejects so each can be resolved independently. Closes #672. (fd68c070, aa46043a, 3f4fe418)

  • Per-connection mid-stream send behavior (Steer vs Queue) — A new submenu in the Settings → AI connection context menu lets you choose what happens when you send a follow-up while the agent is mid-stream. Steer keeps today's behavior (redirect attempts to inject the new message into the live turn); Queue finishes the current turn cleanly and replays the queued message after onProcessingStopped. The two modes have meaningfully different failure shapes — Claude's emulated steer can produce steer_undelivered if no tool fires before the turn ends, paying tokens for nothing; Pi's .steer() is native and has no such failure mode. Defaults are picked per-provider at connection-create time (anthropic → queue, pi/pi_compat → steer) and stored in connection.midStreamBehavior. 4 new i18n keys ×ばつ 7 locales. Closes the queue-vs-steer half of conversations around mid-stream UX. (35a4ca2e, f346035a)

  • Per-model image support toggle in the chat-input picker — Custom-endpoint (pi_compat) connections now expose a one-click image toggle next to each model in the chat-input model picker. When you stage an image but the active model resolves to supportsImages !== true, an inline pre-flight banner appears above the attachment preview with an "Enable image support" action. Both surfaces resolve through shared helpers (modelSupportsImages / setModelSupportsImages) so they can't drift. The toggle now also renders in the single-model picker branch (used for pi_compat connections with 0 or 1 models + a defaultModel). Storage schema unchanged — flips connection.models[i].supportsImages. Built-in anthropic / pi catalogs stay SDK-owned and not editable from this surface. Closes #679. (f36c0833, bba2d726, 31ddd5aa)

  • Tool-result threshold scales with model context window — The fixed 15k-token threshold for large-response handling burned 25 % of context per tool result on a 64k-window model, and three or four moderate Read/Grep results could overflow even after Pi's auto-compaction. New tokenLimitFor(contextWindow) helper: floor 2k, ceiling 15k, linear contextWindow * 0.10 between (64k → 6.4k, 128k → 12.8k). Pi-side tool wrapper sources agent.state.model.contextWindow per call so the threshold tracks set_model mid-session. ClaudeAgent reads from the usage tracker. Addresses gap 1 from #666. (0d3c2796)

Improvements

  • Settings → Messaging i18n consolidation — Settings → Messaging mixed English fragments into every non-en locale (Hungarian showed "Reconfigure" / "Disconnect" / "Connect" alongside translated copy) because shared verbs were duplicated across per-platform namespaces and three keys resolved via t(..., { defaultValue: ... }) with no real entry. Added 7 common.* action verbs (configure / connect / disable / disconnect / more / reconfigure / reconnect) translated to all 6 non-en locales, replaced 8 call sites in MessagingSettingsPage.tsx, deleted 9 redundant per-platform keys ×ばつ 7 locales (63 cells removed), and routed the hardcoded PLATFORM_API_DESCRIPTION constant through new apiType keys. Backfilled 8 platform-specific gap-fills that had been left as English. Net: 14–17 untranslated values per locale → 2–5 (only legitimate cognates like "Region" remain). Adding a new platform no longer requires duplicating verb translations. (bd575ed1)

  • Locale-file sort guard — Across en/de/es/hu/ja/pl/zh-Hans.json, 96 of 1393 keys per locale were out of alphabetical order — identical disorder confirmed past mass-translate scripts preserved insertion order. New scripts/sort-locales.ts (run via bun run sort-locales, or bun run lint:i18n:sorted for CI/check mode) normalizes in place. The pre-commit hook (scripts/lint-i18n-staged.sh) now blocks commits that stage unsorted locales with a "Fix: bun run sort-locales" hint, and validate:ci includes the same check. Net change: zero keys added/removed; the locale-parity test suite goes 58 / 7 → 65 / 0. (3a40b5a5, 3f4fe418)

  • Pi SDK uplift to 0.72.1 — Bumps @mariozechner/pi-ai, pi-agent-core, and pi-coding-agent from 0.70.2 to 0.72.1 across all four package.json files. Drops the now-removed google-gemini-cli and google-antigravity entries from PI_EXCLUDED_PROVIDERS. The 0.72.0 release replaced compat.reasoningEffortMap with model-level thinkingLevelMap; verified Craft's buildCustomEndpointModelDef sets neither field so existing custom-endpoint registrations are unaffected. Adjacent fixes picked up: undici body/headers idle timeouts disabled for long streams (#3715), Anthropic stream-end-as-error handling (#3936), DeepSeek V4 reasoning compat, GPT-5.5 Codex support, websocket-cached transport for OpenAI Codex (#4083). (522a727f)

  • HTTP MCP validation no longer spawns a subprocessvalidateMcpConnection() previously spawned a full Claude Code subprocess via the Agent SDK's query() just to call mcpServerStatus(). On macOS the Electron sandbox killed that subprocess with SIGKILL before validation could finish, so every HTTP MCP source_test failed even when the server was healthy. Now uses CraftMcpClient directly (which already supports HTTP transport and runs a listTools() health check inside connect()); drops the subprocess, the Anthropic env-var swapping, the Claude credential pre-check, and the dead claudeApiKey/claudeOAuthToken/model fields from the validation config. Net −231 / +119 lines. Fixes #697. (f0a12c4e)

  • API source probe honors testEndpoint.body and method; tool descriptions slimmed — POST-only API endpoints reliably 500'd from an empty probe body because the configured testEndpoint.body and testEndpoint.headers were ignored. The basic probe also now honors testEndpoint.method instead of the HEAD→GET-on-405 dance that silently passed POST-only endpoints. Separately, guide.md is no longer inlined into the API tool description on every LLM request — the agent's PrerequisiteManager already forces a Read of sources/{slug}/guide.md before any api_{slug} call, so the guide always lands in conversation history once. For OpenAPI-imported sources this saves tens of KB per request and removes the bloat that pushed #683's payload past the relay limit. (589a51bf)

  • IPC inventory script auto-updates the test snapshotscripts/ipc-inventory.ts now rewrites the auto-generated EXPECTED_CHANNELS block in ipc-channels.test.ts in place instead of just printing a migration report. Run it after adding/removing/renaming any RPC_CHANNELS entry. (aa46043a)

Bug Fixes

  • Custom-endpoint supportsImages toggle now propagates to the live Pi subprocess — Toggling per-model image support wrote to disk but never reached the running Pi subprocess, so the model kept seeing attached images replaced by Pi SDK's "(image omitted: model does not support images)" placeholder. Two compounding issues: getOrCreateAgent gated the in-place runtime refresh on managed.isProcessing (which sendMessage had just flipped to true, making the refresh branch dead code), and the llmConnections.SAVE handler had no notification path to active sessions. Now SAVE fires the runtime push detached (so config persistence isn't gated on N ×ばつ 15s per-session timeouts), the gate uses agent.isProcessing() only, and a per-session agentRefreshLocks mutex serializes concurrent refreshes so agent.chat() can't fire against a still-applying update. Restart-required field changes (piAuthProvider, slug, auth/provider routing — fields the update_runtime_config IPC can't propagate) now route straight to dispose + recreate via a separate buildRestartRequiredSignature. (81a6f195, 6c0fec02, ebf01805, f0bbfe96)

  • Vision toggle no longer blanks the trigger button on string-shaped models — Promoting a models: ['gpt-4o']-shaped string entry to an object via the new image toggle dropped the model name (no name field), so the picker's trigger button rendered blank. setModelSupportsImages now seeds name: id, shortName: id when promoting; defensive m.name ?? stripPiPrefixForDisplay(m.id) fallback at the three picker display sites also r...

Read more
Loading
ninjaeon reacted with rocket emoji
1 person reacted
Previous 1 3 4 5 6 7 8
Previous

AltStyle によって変換されたページ (->オリジナル) /