- Simplified null/empty checks across TypeScript codebase using optional chaining operator (?.) for improved readability.
- Replaced explicit null checks in validation logic with optional chaining in oauth-discovery, gemini-cli, claude, zai, and lsp modules.
- Updated error handling in Rust command invocation to use double question mark operator (??) for cmd_result.
- Consolidated null validation patterns across tools (bash-skill-urls, browser, gemini-image, resolve) and keybindings using optional chaining.
- Added autoresearch extension with autonomous experiment loop supporting init, run, and log experiment tools for metric-driven optimization.
- Added widget placement system enabling extensions to position UI components above or below the editor via ExtensionWidgetOptions.
- Added dashboard controller with interactive overlay for viewing experiment results, metrics, and progress with keyboard navigation.
- Removed auto-correction logic for off-by-one range edits in hashline editor to preserve user intent in patch operations.
- Added state reconstruction utilities to parse autoresearch.jsonl logs and rebuild experiment state across sessions.
- Added comprehensive type definitions and helper utilities for metric parsing, ASI validation, and process management.
* feat: auto-reconnect MCP servers on connection loss
When an HTTP SSE stream drops (server restart, network interruption),
the transport fires onClose, and the manager proactively reconnects
with retry backoff (500ms, 1s, 2s, 4s). Tools are kept in the registry
during reconnection so they remain selected and available to the agent.
If proactive reconnection fails, stale tools stay registered. When the
agent calls one, the tool bridge detects the retriable connection error
(ECONNREFUSED, ECONNRESET, stale session 404/502/503, etc.), triggers
reconnectServer on the manager, and retries the call once on the fresh
connection. Concurrent reconnect attempts for the same server are deduped.
connectToServer now always installs a default onRequest handler for ping
and roots/list (using getProjectDir()), so all connections -- including
short-lived test/probe ones -- properly respond to server-initiated
requests during initialization.
Post-connection setup (resources, prompts, subscriptions) is extracted
into a shared #loadServerResourcesAndPrompts method used by both initial
connection and reconnection paths.
Add /mcp reconnect <name> command for manual recovery after extended
outages where both proactive and reactive reconnection have failed.
* docs: add changelog entry for MCP auto-reconnect
* fix: address P1 review findings in MCP reconnection
- Save server configs before connection attempt so deferred tools can
reconnect even when the initial connection timed out (P1-1)
- Make waitForConnection() and getConnectionStatus() aware of in-flight
reconnections so callers wait instead of failing immediately (P1-2)
- Add epoch counter incremented on disconnectAll() and checked in
connectAndWireServer() to invalidate stale reconnect attempts that
outlive a manager reset/reload (P1-3)
- Skip servers with pending reconnections in connectServers() to prevent
parallel connection attempts for the same server
* fix: deferred tool reconnect and non-blocking transport teardown
- DeferredMCPTool.execute now reconnects when getConnection() fails
("MCP server not connected"), not only on network errors from
callTool. Servers that missed the startup window can now be woken
by the first tool call against their cached tools. (P1-4)
- #doReconnect fire-and-forgets the old transport close instead of
awaiting it. HttpTransport.close() sends a DELETE with 30s timeout;
blocking here delayed the first reconnect attempt by that amount
on every server restart. (P1-5)
* fix: abort-aware reconnect waits and preserve tool selection on reconnect
- Wrap all reconnect() awaits with withAbort(signal) so user
cancellation (Esc) interrupts the reconnect backoff loop instead
of blocking for up to 7.5s. Applies to MCPTool (1 site) and
DeferredMCPTool (2 sites). (P2-1)
- Remove activateDiscoveredMCPTools call from /mcp reconnect handler.
refreshMCPTools already preserves the user's prior MCP tool
selection; the extra activation was silently opting into all
server tools including ones the user had not enabled. (P2-2)
* fix: rebind MCPTool connection after reconnect, add stdio retriable error
- MCPTool.connection is now mutable; after a successful reconnect retry,
this.connection is rebound to the fresh connection so subsequent calls
on the same instance (e.g. batched tool calls) use it instead of
triggering another reconnect cycle. (P2-3)
- Add "Transport closed" to RETRIABLE_PATTERNS. StdioTransport rejects
pending requests with this message when the subprocess dies, which
should trigger the reconnect path just like HTTP transport errors. (P2-4)
---------
Co-authored-by: Miroslav Drbal <miroslav.drbal@gendigital.com>
Co-authored-by: Can Bölük <can1357@users.noreply.github.com>
- Added automatic deduplication of identical context files by content, keeping the closest (lowest depth) copy when duplicates are discovered.
- Implemented dedupeExactContextFiles() function to filter duplicate context entries in both explicit and discovered file lists.
- Added 3 test cases covering deduplication of explicit context entries, discovered context entries, and preservation of distinct entries.
- Extracted OpenAI compatibility detection and resolution logic into dedicated `openai-completions-compat` module.
- Refactored `detectCompat()` and `getCompat()` to delegate to new compat module functions with simplified conditional logic.
- Fixed OAuth redirect URI validation to preserve exact configured values without trailing slash normalization.
- Improved session deletion to return boolean status and display error messages in UI instead of silently failing.
- Added `/session delete` command with Delete key support and confirmation dialogs for session management.
- Schedule auto-removal of completed/abandoned tasks after ~1 minute delay
- Strip already-done tasks when restoring session from branch history
- Add todo_auto_clear event to trigger UI refresh on removal
- Add blank line before Todos header for visual spacing
Two /move bugs on Windows:
1. Quoted absolute paths (e.g. /move "C:\...") were treated as relative
because surrounding quotes weren't stripped before path.isAbsolute().
2. /move before any model response threw ENOENT because the session
.jsonl file hadn't been created on disk yet (lazy-persist).
Changes:
- Extract stripOuterDoubleQuotes() helper in path-utils.ts, use in
handleMoveCommand() with empty-after-strip guard
- Guard session file rename with existsSync in moveTo(), leaving
artifact dir rename independently guarded
- Guard #rewriteFile() with hadSessionFile || hasAssistant to preserve
lazy-persist while still updating header cwd for existing files
- Add comprehensive test suite (13 tests) covering all moveTo() edge
cases including header-only sessions, deferred persistence, and
artifact migration
- Added `moveCursorToMessageStart()` and `moveCursorToMessageEnd()` prompt actions for cursor navigation to message boundaries.
- Exposed editor methods for cursor movement to message start and end positions in InputController keybindings.
- Implemented message boundary navigation in Editor class with private helper methods for cursor positioning.
- Removed remote compaction settings test suite to align with feature deprecation.
* feat: spill large tool results to artifacts, show tail
- Add centralized spillLargeResultToArtifact() in wrappedExecute pipeline
- Tool results exceeding 50KB saved as session artifacts via saveArtifact()
- Content truncated to tail (20KB / 500 lines) instead of head
- Truncation notice includes artifact:// reference for full output retrieval
- Skip spill when tool already saved its own artifact (bash/python/ssh)
- Update formatFullOutputReference to use action-oriented wording
* feat: per-turn token usage display on assistant messages
* fix: TS errors in output-meta truncation fields
Three early-return paths in #runAutoCompaction emitted auto_compaction_end
with result=undefined, aborted=false, and no errorMessage when compaction
was legitimately not needed (no model selected, no candidate models
available, or nothing to compact yet). The event-controller had no way to
distinguish these benign skips from a genuine failure, and fell through to
show the warning:
'Auto context-full maintenance failed; continuing without maintenance'
This was visible after a successful compaction: the next threshold check
would find nothing new to compact (prepareCompaction returns null), emit a
soft-skip event, and trigger the false warning.
Add skipped?: boolean to the auto_compaction_end event type and set it on
the three soft-skip paths. Update the event-controller to treat skipped
events as silent no-ops. Propagate the field through the extension and
hook AutoCompactionEndEvent interfaces so extensions can observe the
distinction.
* fix(memories): isolate Phase 2 consolidation per project working directory
The global memory consolidation job used a single 'global' job key,
causing all projects to share one Phase 2 slot. Whichever project
claimed it first got every project's stage1 outputs written into its
memory directory — cross-project contamination.
Root cause:
- GLOBAL_KEY = 'global' was a single key shared by all projects
- listStage1OutputsForGlobal() had no cwd filter — returned ALL
stage1 outputs across all projects
- markGlobalPhase2Succeeded/Failed/Unowned all operated on the same
single global job row
Fix:
- Replace GLOBAL_KEY constant with globalJobKey(cwd) function that
namespaces the job key per project: 'global:/path/to/project'
- Add cwd parameter to all Phase 2 storage functions so each project
maintains its own job slot in the jobs table
- Filter listStage1OutputsForGlobal() by t.cwd = ? so each project
only consolidates its own thread outputs
- Thread cwd from session.sessionManager.getCwd() through runPhase2()
to all storage calls
- Add cwd to markStage1SucceededWithOutput/NoOutput so enqueueGlobal
Watermark targets the correct per-project job key
- Add cwd parameter to enqueueMemoryConsolidation() public API and
update its only external caller (command-controller)
Closes#369
* test(memories): add isolation tests for per-project Phase 2 consolidation
Three tests covering the regression fixed in the previous commit:
- listStage1OutputsForGlobal filters outputs by cwd (no cross-project leak)
- enqueueGlobalWatermark creates separate job rows keyed per-project
- tryClaimGlobalPhase2Job claims only the requested project's slot and
leaves the other project's job independently claimable
* docs: add inline comments for memory isolation fix and tests
---------
Co-authored-by: Rens Tillmann <rens@super-forms.com>
- Added pluggable code search provider system supporting Exa and grep.app with provider selection via `providers.codeSearch` setting.
- Removed Exa-specific tools (`exa_linkedin`, `exa_company`, `exa_search_deep`, `exa_crawl`) and simplified web search tools to focus on core functionality.
- Refactored code search from Exa-only to provider-agnostic architecture with new `code_search` tool supporting context-aware grep.app queries and Exa fallback.
- Removed `exa.enableLinkedin` and `exa.enableCompany` configuration settings in favor of provider-based architecture.
- Added comprehensive test coverage for code search functionality including grep.app result normalization and provider fallback behavior.
- Added `/copy` command subcommands (code, all, cmd, last) for flexible code block and command copying.
- Added support for copying last executed bash or python command via `/copy cmd` subcommand.
- Refactored handleCopyCommand() to route subcommands with dedicated private methods for each copy operation.
- Added regex-based code block extraction from markdown with fallback warnings for missing blocks.
* Add OAuth token refresh for MCP connections
Proactive refresh with 5-minute buffer before token expiry, plus
retry on 401/403 with automatic token refresh for HTTP transports.
Persist tokenUrl, clientId, and clientSecret in auth config so
refresh can happen without re-prompting the user.
* docs(coding-agent): updated CHANGELOG for MCP OAuth token refresh
- Introduced SubmittedUserInput type to track submission state including cancelled and started flags. Added startPendingSubmission, cancelPendingSubmission, markPendingSubmissionStarted, and finishPendingSubmission methods to manage the lifecycle of user input submissions. Enhanced escape key handling to prioritize canceling pending optimistic submissions before aborting active sessions.
- Extracted loading animation lifecycle management into centralized ensureLoadingAnimation() method.
- Consolidated duplicate loading animation setup across event-controller and interactive-mode into single reusable method.
- Updated showError() to properly clean up loading animation state when errors occur.
- Added comprehensive test coverage for InputController escape key behavior with optimistic submission.
The manual /compact command path in executeCompaction() called
rebuildChatFromMessages() but never added the compactionSummary
message to the chat. The auto-compaction path in event-controller
explicitly adds it, but the manual path was missing this step.
Capture the CompactionResult returned by session.compact() and
render the summary via addMessageToChat(), matching the behavior
of the auto-compaction flow.
Co-authored-by: Miroslav Drbal <miroslav.drbal@gendigital.com>
- Extracted OAuth identifier logic into public functions extractOAuthCredentialIdentifiers and extractOAuthTokenIdentifiers.
- Replaced single credentialIdentity string with multi-identifier resolveCredentialIdentifiers returning string[] for flexible matching.
- Changed credential deduplication from email-based to accountId-based matching in replaceAuthCredentialsForProvider.
- Updated auth-storage tests to verify accountId-prioritized deduplication behavior across soft-disable and hard-delete scenarios.
- Added documentation comments in coding-agent modules explaining partial JSON preservation for streaming tool previews.
- Documented streaming tool preview requirements and render paths in AGENTS.md.
- Added `env` parameter to bash tool for safe environment variable passing without shell re-parsing.
- Added support for rendering partial environment variable assignments in command preview during streaming.
- Updated bash tool prompt to recommend `env` parameter for multiline, quote-heavy, and untrusted values.
- Refactored tool execution component to conditionally merge partial JSON arguments during streaming.
- Added helper functions for environment variable normalization, escaping, and formatting.
- Introduced Effort enum and ThinkingConfig metadata for per-model reasoning capabilities with min/max effort levels.
- Migrated thinking level API from string-based ThinkingLevel to structured Effort enum across agent and AI packages.
- Added model-thinking module with effort mapping, policy application, and semantic versioning utilities for provider-specific thinking modes.
- Removed supportsXhigh() function and replaced effort clamping with model-aware validation using ThinkingConfig metadata.
- Expanded models.json with thinking configuration objects for 50+ models including Claude, Gemini, and OpenAI variants.
- Added Python analysis scripts for edit tool usage patterns and tool invocation stream processing.
- Added serviceTier option to OpenAI providers for controlling processing priority and cost across agent, completions, responses, and codex APIs.
- Added providerPayload field to messages for transport-native history reconstruction in OpenAI Responses and Codex APIs.
- Added /fast slash command and serviceTier setting to coding-agent for toggling OpenAI priority mode with fast mode indicator.
- Added remote compaction support with encrypted reasoning preservation for OpenAI models in coding-agent.
- Removed usage caching layer across all providers and refactored UsageFetchContext to eliminate cache and now dependencies.
- Fixed OpenAI Codex streaming service_tier inclusion, provider retry logic with exponential backoff, and email-based credential deduplication.
* idiomatic rust fixes
* idiomatic rust fixes
* display an image if we are fetching an image
* MIME type strictness
* codex nagging me
* codex nagging
* handoff instead of compaction as context filled strategy and surfacing
* handoff instead of compaction as context filled strategy and surfacing p2
* handoff instead of compaction as context filled strategy and surfacing p3
* handoff instead of compaction as context filled strategy and surfacing p4
* handoff instead of compaction as context filled strategy and surfacing p5
* handoff instead of compaction as context filled strategy and surfacing, fixes
* failing fetch test from the fetch tool updates
* handoff focus prompt skeleton
* handoff focus prompt skeleton p2
* fetch bugs
* further codex improvements
* further codex improvements
---------
Co-authored-by: Brit <lol@no.com>
- Corrected provider selection case labels from flat names to namespaced keys (webSearchProvider -> providers.webSearch, imageProvider -> providers.image).
- Expanded web search provider options to include brave, kimi, kagi, and synthetic providers.
- Updated option interfaces, param builders, and stream functions to use unified `reasoning` field.
- Added `resolveOpenAiReasoningEffort()` to centralize xhigh clamping logic.
- Replaced type casts with `castApi()` helper and fixed test option names.
- Updated coding-agent and benchmark references for consistency.
- Extracted thinking module with ThinkingEffort, ThinkingLevel, and ThinkingMode types to centralize reasoning configuration across packages.
- Migrated ThinkingLevel type from pi-agent-core to pi-ai package with new validation functions parseThinkingLevel() and getAvailableThinkingLevel().
- Consolidated thinking level constants and descriptions into reusable exports (ALL_THINKING_LEVELS, THINKING_MODE_DESCRIPTIONS) for consistent UI display.
- Removed local thinking-effort-label utility and replaced formatThinkingEffortLabel() with centralized formatThinking() function from pi-ai.
- Refactored thinking mode handling to distinguish ThinkingSelector (user-facing with 'off' option) from ThinkingEffort (provider-level).
- Added Bun version validation at startup to enforce minimum version 1.3.7 for JSONL session parsing.
- Fixed `/resume` and `--resume` flags silently failing on older Bun runtimes by adding version check.
Fixes#277
- Converted clipboard copy operation from async to synchronous execution across native and TypeScript layers.
- Simplified copy_to_clipboard return type from task::Async<()> to Result<()> in Rust implementation.
- Removed promise chains and async/await from clipboard handlers in command and input controllers.
- Updated clipboard module documentation to explain synchronous execution avoids AppKit pasteboard warnings.
- Reordered fix:rs script to run cargo fmt before cargo clippy for consistent formatting.
- Added `/login <provider>` command for direct OAuth provider login with automatic selector routing.
- Added Kagi API key authentication support as new OAuth provider across ai and coding-agent packages.
- Added optional `providerId` parameter to `showOAuthSelector()` for direct provider selection without manual input.
- Simplified web search result formatting by removing empty sections (Answer, Sources, Meta, Related).
- Fixed MCP tool schema dereferencing and Ajv validation warnings for non-standard format keywords.
- Refactored OAuth login/logout logic into extracted handler methods for improved maintainability.