这是indexloc提供的服务,不要输入任何密码
Skip to content

Swap WUI daemon connection for REST API #355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

balanceiskey
Copy link
Collaborator

@balanceiskey balanceiskey commented Jul 25, 2025

What problem(s) was I solving?

The WUI (Web UI) was communicating with the HLD daemon using a legacy Tauri-based JSON-RPC client, which limited development flexibility and made it harder to maintain consistency with other components that use the REST API. Additionally, the HTTP server was disabled by default (port 0), preventing REST API usage.

Key issues being addressed:

  • Inconsistent communication patterns across the codebase (JSON-RPC vs REST)
  • Tauri-specific implementation limiting future development options
  • HTTP server disabled by default preventing REST API access
  • Multiple SSE connections causing performance issues and server lockup
  • TypeScript compatibility issues with SDK integration

What user-facing changes did I ship?

Configuration Changes:

  • HTTP server now enabled by default on port 7777 (was previously disabled)
  • Added environment variable support for daemon configuration (HUMANLAYER_DAEMON_HTTP_PORT, HUMANLAYER_DAEMON_HTTP_HOST)
  • Added .env.example file documenting configuration options

Performance Improvements:

  • Consolidated SSE connections to a single connection, reducing browser resource usage
  • Fixed server lockup issues when navigating in/out of SessionDetail views
  • Improved session loading with proper skeleton UI states

Developer Experience:

  • Better error handling and connection retry logic
  • Enhanced CORS support with client identification headers

How I implemented it

1. HTTP Server Configuration (hld/)

  • Changed default HTTP port from 0 (disabled) to 7777 in config/config.go
  • Added configuration documentation in hld/README.md
  • Enhanced CORS headers to support client identification (X-Client, X-Client-Version)
  • Added health check logging exclusion for cleaner logs

2. SDK Integration (hld/sdk/typescript/)

  • Fixed SDK build configuration to use ES2020 modules instead of CommonJS for browser compatibility
  • Updated TypeScript client to handle proper response types (CreateSessionResponseData)
  • Added support for initOverrides in session message requests

3. WUI Migration (humanlayer-wui/)

  • Replaced Tauri JSON-RPC client with HTTP client using HLD SDK
  • Created HTTPDaemonClient class with complete REST API implementation
  • Added transform functions for Session, Approval, and Message types to handle both camelCase (SDK) and snake_case (UI) formats
  • Implemented connection retry logic with 3 attempts and SSE event subscriptions

4. State Management Refactoring

  • Consolidated SSE subscriptions to single connection in Layout.tsx
  • Added activeSessionDetail to Zustand store for centralized session state
  • Removed duplicate SSE connections from useSession hook
  • Updated hooks to use centralized connection management

5. Type Safety Improvements

  • Added Legacy interfaces to maintain backward compatibility with snake_case UI
  • Fixed undefined event ID handling throughout SessionDetail components
  • Updated enum imports to work with SDK const objects vs TypeScript enums
  • Added comprehensive type mapping between SDK and UI formats

How to verify it

  • I have ensured make check test passes

Manual Testing Steps:

  • Start the daemon with hld start and verify it runs on port 7777
  • Launch WUI and verify connection to daemon works
  • Navigate between sessions and confirm no server lockup issues
  • Test session creation, approval actions, and real-time updates
  • Verify environment variable configuration works (VITE_HUMANLAYER_DAEMON_URL)
  • Confirm reduced browser connection usage compared to previous version

Description for the changelog

feat(wui): migrate from JSON-RPC to REST API communication

  • Migrated WUI from Tauri JSON-RPC to HTTP client using HLD SDK
  • Enabled HTTP server by default on port 7777 with configurable environment variables
  • Consolidated SSE connections to improve performance and prevent server lockup
  • Added comprehensive type transformations between camelCase (SDK) and snake_case (UI)
  • Fixed SDK ES module compatibility for browser environments
  • Enhanced connection retry logic and error handling

Important

Replaces Tauri JSON-RPC client with REST API client, enabling HTTP server by default and improving performance and developer experience.

  • Behavior:
    • Replaces Tauri JSON-RPC client with REST API client using HTTPDaemonClient in client.ts.
    • Enables HTTP server by default on port 7777 in config.go.
    • Adds environment variable support for daemon configuration.
  • Performance:
    • Consolidates SSE connections to a single connection in Layout.tsx.
    • Fixes server lockup issues in SessionDetail views.
  • Developer Experience:
    • Adds HTTPDaemonClient class with complete REST API implementation in http-client.ts.
    • Updates TypeScript client for proper response handling.
    • Enhances CORS support with client identification headers.
  • State Management:
    • Refactors state management to use Zustand store in AppStore.ts.
    • Adds activeSessionDetail to store for centralized session state.
  • Type Safety:
    • Adds legacy interfaces for backward compatibility with snake_case UI.
    • Updates type mappings between SDK and UI formats.
  • Misc:
    • Adds .env.example for configuration documentation.
    • Updates README.md for new configuration options.

This description was created by Ellipsis for 70d7b54. You can customize this summary. It will automatically update as commits are pushed.

balanceiskey and others added 16 commits July 24, 2025 14:18
Changed default HTTP port from 0 (disabled) to 7777 to support REST API migration.
Added configuration documentation for HTTP server environment variables.
Replaced Tauri-based JSON-RPC client with HTTP client using HLD SDK.
Added legacy type interfaces to maintain backward compatibility with
existing UI code that expects snake_case properties.

- Created HTTP client with connection retry and SSE support
- Added configuration for daemon URL with environment variables
- Updated type definitions to use SDK types with legacy mappings
- Added SDK dependency and built it for local development

The WUI remains a Tauri desktop app - only daemon communication changed.
…rmations

- Add HTTPDaemonClient class with complete REST API implementation
- Implement transform functions for Session, Approval, and Message types
- Handle both camelCase (SDK) and snake_case (UI) property formats
- Add connection retry logic with 3 attempts
- Support SSE event subscriptions with automatic reconnection
- Replace Tauri-based client with HTTP implementation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Import SessionStatus, ApprovalStatus, and EventType as values (not type-only)
- Add Legacy interfaces to maintain backward compatibility with snake_case UI
- Map SDK types to legacy types for gradual migration
- Add comprehensive TODO explaining future refactor plan
- Fix SessionSnapshot to map to FileSnapshotInfo

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Replace unlisten with unsubscribe for event subscriptions
- Fix SDK method signatures (health, listApprovals, getRecentPaths)
- Update event structure access (event.type instead of event.event.type)
- Fix approvals response handling (array directly, not object)
- Update continueSession response property names
- Add proper subscription cleanup in all hooks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove references to non-existent ApprovalStatus.Resolved
- Add null checks for date/time formatting functions
- Fix model enum mapping (claude-3-5-sonnet-20241022 → sonnet)
- Update event handlers to use correct event structure
- Fix approvals response handling in Layout component
- Remove non-existent bulk_archive_sessions property reference

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- EventType is exported as a const object in SDK, not an enum
- Import as type-only since values are passed as string literals
- Fixes "Indirectly exported binding name 'EventType' is not found" error

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- SessionStatus and ApprovalStatus are const objects in SDK, not enums
- Import with aliases and re-export as const assignments
- Export both the value and type for each
- Fixes "Indirectly exported binding name is not found" errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Change tsconfig.json module format from commonjs to ES2020
- Fix "exports is not defined" error when SDK loads in browser
- Revert namespace import workarounds now that SDK exports ESM
- SDK now uses standard ES module syntax (export/import)

This was the root cause of all the import/export binding errors.
The SDK was built as CommonJS which doesn't work in browser environments.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Add X-Client and X-Client-Version headers to the allowed CORS headers
in the HTTP server to support client identification in REST API calls.
- Remove duplicate connection logic from Layout.tsx
- Use centralized connection management from useDaemonConnection hook
- Enable periodic health checks every 30 seconds
- Single source of truth for daemon connection state
- Clean up debug logging added during investigation

This fixes the missing periodic health checks by properly utilizing
the hook that was designed for connection management.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Major refactoring to eliminate duplicate SSE connections and improve performance:

- Consolidated all SSE subscriptions to a single connection in Layout.tsx
- Added activeSessionDetail to Zustand store to centralize session state
- Removed duplicate SSE connections from useSession hook
- Updated useConversation to read from and update the store
- Fixed session loading to show skeleton UI properly
- Added proper loading/error states in activeSessionDetail
- Removed unnecessary useSession hook abstraction
- Fixed daemon client method names (getConversation not getSessionMessages)

This should significantly reduce browser connection usage and prevent the
server lockup issues when navigating in/out of SessionDetail views.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Import SessionStatus in appStore.ts
- Fix launchSession return type to use CreateSessionResponseData
- Update useSessions to use correct response properties (sessionId/runId)
- Fix parameter handling in http-client for both camelCase and snake_case
- Convert getRecentPaths response from string[] to RecentPath[]
- Add missing properties to minimal session object in SessionDetailPage
- Fix undefined handling in useSessionActions

Remaining errors are related to event IDs that might be undefined in SessionDetail components.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add checks for undefined event IDs before using them
- Filter events with undefined IDs in navigation and approval hooks
- Use non-null assertions after filtering
- Add undefined checks in mouse event handlers
- Prefix unused parameters with underscore

All TypeScript errors are now resolved.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@balanceiskey balanceiskey changed the title Sundeep/eng 1764 swap wui daemon connection for rest api Swap WUI daemon connection for REST api Jul 25, 2025
@balanceiskey balanceiskey changed the title Swap WUI daemon connection for REST api Swap WUI daemon connection for REST API Jul 25, 2025
@balanceiskey balanceiskey marked this pull request as ready for review July 25, 2025 21:43
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to 70d7b54 in 2 minutes and 56 seconds. Click for details.
  • Reviewed 3733 lines of code in 35 files
  • Skipped 1 files when reviewing.
  • Skipped posting 7 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. humanlayer-wui/src/components/internal/SessionDetail/eventToDisplayObject.tsx:79
  • Draft comment:
    JSON.parse is used directly assuming tool_input_json is non-null. It’s safer to check if tool_input_json exists before parsing to avoid runtime errors.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
2. humanlayer-wui/src/components/internal/SessionDetail/eventToDisplayObject.tsx:355
  • Draft comment:
    The display logic function is very long; consider refactoring into smaller sub‐components for maintainability.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
3. humanlayer-wui/src/hooks/useConversation.ts:35
  • Draft comment:
    Error count stops polling after 3 errors. Verify whether this behavior is desired or if a more robust retry mechanism is needed.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 30% <= threshold 50% The comment is asking the PR author to verify if the behavior is desired, which violates the rule against asking for confirmation of intention. However, it does point out a potential issue with the error handling mechanism, which could be useful if rephrased to suggest a more robust retry mechanism directly.
4. humanlayer-wui/src/lib/daemon/http-client.ts:299
  • Draft comment:
    In subscribeToEvents, if connection fails the fallback polling strategy is initiated. Consider documenting the retry/fallback behavior to make future maintenance easier.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 20% <= threshold 50% The comment suggests documenting the retry/fallback behavior, which is a request for documentation rather than a code suggestion or a request for a test. It doesn't align with the rules as it doesn't provide a specific code suggestion or highlight a potential issue with the code itself.
5. humanlayer-wui/src/stores/appStore.ts:424
  • Draft comment:
    The clearNotificationsForSession action rebuilds a set filtering out IDs including the session ID. Consider whether matching substring is robust enough, or if a more structured notification identifier should be used.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
6. humanlayer-wui/bun.lock:757
  • Draft comment:
    Typo detected: The dependency 'devlop' in the dependency list for 'hast-util-to-jsx-runtime' appears suspicious. Did you mean 'develop' or is this an intentional package name?
  • Reason this comment was not posted:
    Comment was on unchanged code.
7. humanlayer-wui/bun.lock:893
  • Draft comment:
    Typographical error: It seems that "devlop" might be a misspelling. Did you mean "develop"?
  • Reason this comment was not posted:
    Comment was on unchanged code.

Workflow ID: wflow_eIudZaQz0SVLxHxe

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

updateSessionStatus: (sessionId: string, status: string) =>
set(state => ({
sessions: state.sessions.map(session =>
session.id === sessionId ? { ...session, status: status as any } : session,
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider using the proper SessionStatus type instead of casting status as any in updateSessionStatus. This could improve type safety.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant