Skip to content

Conversation

@charliecreates
Copy link
Contributor

Restore the spinning state of the Code indicator while an AI response is actively streaming inside a code segment.

Context

Regression: the Code icon stopped spinning during streaming, even when the stream was currently producing code. Prior logic tied the loading state to overall streaming/code presence rather than whether the active stream position was inside a code fence.

Changes

  • Detect "streaming inside code" from the current AI message text by counting unpaired triple-backtick fences and derive a boolean.
  • Override the code control's loading flag in the header based on that boolean so the Code icon spins only while the stream is inside code.
  • Keep all other controls/behaviors unchanged.
  • Tests: add integration-style tests that simulate streaming with code blocks (single and multiple segments) and assert the indicator spins.

Impact

Verification

pnpm check
# format: ok
# typecheck: ok
# tests: 66 files, 364 passed, 4 skipped

Closes #220

jchris and others added 30 commits July 27, 2025 08:37
* WIP

* LLM instruction for callai prooxy

* fix tests.

* fix: update auth flow test to check for relative connectUrl path

* fix: update titleGenerator to use environment variable for CALLAI endpoint

* fix: remove  X-VIBES-Token header from token requests

* revert prompts

* Simplify proxy configuration

* chore: update package dependencies and lockfile to latest versions

* fix: update API_BASE_URL to use new production domain

* feat: add APP_HOST_BASE_URL env var and update app URL construction

* style: format appUrl assignment with line break for better readability

---------

Co-authored-by: J Chris Anderson <[email protected]>
this may fix the black screen of death
* feat: add code editing and saving functionality in preview editor

* feat: add save button with code change tracking in ResultPreview

* fix: remove problematic test file to make pnpm check pass

Remove failing saveCode.test.tsx that had AuthProvider context issues.
The core save functionality is already tested through integration and
the feature works correctly in the application.

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

Co-Authored-By: Claude <[email protected]>

* feat: implement editable Monaco Editor with intelligent save behavior

Add full editable code functionality to Monaco Editor with smart CREATE/UPDATE logic:
- Make Monaco Editor editable with live change tracking and save button
- Implement saveCodeAsAiMessage that creates "Edit by user" + "User changes" message pairs
- Smart logic: CREATE new messages after AI responses, UPDATE when continuing same edit session
- Use UI message array order as source of truth instead of unreliable timestamps
- Add comprehensive debugging with decision context and reasoning logs
- Add save button with custom minidisc icon that appears only when changes exist
- Fix keystroke detection to capture all user input including final keystrokes
- Add enhanced tests covering all functionality and edge cases

Key technical improvements:
- Eliminate timestamp-based sorting issues by trusting message array order
- Use current UI state for decisions instead of separate database queries
- Add detailed logging for debugging CREATE vs UPDATE decision logic
- Ensure consistent behavior between what user sees and save logic

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

Co-Authored-By: Claude <[email protected]>

* refactor: remove debug console.log statements from chat and editor components

* feat: return message ID from saveCodeAsAiMessage and auto-navigate to preview

---------

Co-authored-by: Claude <[email protected]>
Remove email support link until it works
* feat: add format-on-save and auto-formatting to Monaco Editor

- Add formatOnType and formatOnPaste options for real-time code formatting
- Implement format-on-save functionality in handleSave method
- Gracefully handle format errors with fallback behavior

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

Co-Authored-By: Claude <[email protected]>

* feat: add syntax error detection with red LED indicator and disabled save button

- Add Monaco Editor syntax error detection using marker API
- Update LED indicator to show red when selected code has syntax errors
- Modify save button to show error count and disable when errors exist
- Add selectedCodeHasErrors state tracking from Monaco Editor to chat components
- Implement real-time error monitoring with onDidChangeMarkers event listener
- Connect syntax error state through ResultPreview → home.tsx → ChatInterface → MessageList → Message → StructuredMessage → CodeSegment
- Save button now displays "X Error(s)" in red and is disabled when syntax errors present
- LED indicator priority: orange (streaming) → red (errors) → green (selected) → gray (default)

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

Co-Authored-By: Claude <[email protected]>

* fix: enable Monaco Editor JSX syntax error detection

Key fixes to make syntax error detection work:

1. **Language Service Fix**: Changed model language from `jsx` to `javascript`
   - JSX language is for highlighting only, JavaScript language service has error detection
   - Keeps JSX compilation enabled for proper JSX syntax validation

2. **Enable Diagnostics**: Added `setDiagnosticsOptions` with both validation types enabled
   - `noSemanticValidation: false` - enables semantic/type checking
   - `noSyntaxValidation: false` - enables syntax error detection

3. **Enhanced Compiler Options**: Added modern JSX support configuration
   - ESNext modules, Node.js resolution, esModuleInterop
   - Optimized for React JSX with proper factory settings

4. **Improved Error Detection**: Enhanced marker filtering and monitoring
   - Filter by `owner: 'typescript'` to get language service errors only
   - Optimized `onDidChangeMarkers` to only check relevant URI changes
   - Added debug logging to verify error detection (temporary)

Now Monaco Editor will detect JSX syntax errors (unclosed tags, invalid expressions, etc.)
and show them via the red LED indicator and disabled save button.

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

Co-Authored-By: Claude <[email protected]>

* fix: prevent handleCodeChange from overriding syntax error detection

The issue was that handleCodeChange (called on every keystroke) was calling
onSyntaxErrorChange(0) immediately, overriding the correct error count from
the async onDidChangeMarkers listener.

Key fixes:
- Remove immediate syntax error checking from handleCodeChange
- Rely solely on onDidChangeMarkers for accurate error detection
- Add debug logging to trace error state changes
- Monaco's TypeScript language service updates markers asynchronously

This should fix the save button briefly showing red then reverting to blue.

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

Co-Authored-By: Claude <[email protected]>

* refactor: remove selectedCodeHasErrors state and related UI indicators

* feat: enhance Monaco editor error detection with comprehensive marker tracking and debounced checks

* chore: remove debug logging from Monaco editor and syntax error handling

* refactor(result-preview): add manual timeout clearing for syntax error checks

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: CharlieHelps <[email protected]>
* WIP  - feat: add app settings view

* back to original useSession

* change app name input style

* fix(ResultPreviewHeaderContent): guard ShareButton on settings view behind publishedAppUrl; only show when preview ready or published URL exists

* refactor(result-preview): extract exportHtml util and AppSettingsView; remove settings placeholder slot in IframeContent; stabilize useSession callbacks via mergeRef pattern

- IframeContent: drop empty settings slot; add comment clarifying settings render outside iframe
- utils/exportHtml: add generateStandaloneHtml() and downloadTextFile()
- ResultPreview: use new util; factor settings JSX into AppSettingsView
- useSession: use refs for mergeVibeDoc and vibeDoc; create updatedDoc objects and remove callback deps on vibeDoc/merge

Verification: typecheck OK; vitest (scoped) OK for ResultPreviewHeaderContent, ViewControls, useViewState

* test(exportHtml): add Vitest unit tests for generateStandaloneHtml and downloadTextFile

* chore(format): prettier write for tests/exportHtml.test.ts

* fix: eliminate Fireproof CRDT errors in ResultPreview tests

- Add sessionId to mockResultPreviewProps to provide valid session ID
- Mock useSession hook in ResultPreview tests to prevent Fireproof database initialization during testing
- Resolves CRDT "Unknown type, must be binary type" errors introduced by app settings feature

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

Co-Authored-By: Claude <[email protected]>

* fix: eliminate CRDT errors in IframeTemplate test

- Add useSession mock to IframeTemplate.test.tsx to prevent Fireproof initialization
- Resolves "Unknown type, must be binary type" CRDT errors from the iframe messaging test
- Follows same pattern used in ResultPreview.test.tsx fix

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

Co-Authored-By: Claude <[email protected]>

* fix: add missing CALLAI_ENDPOINT to test env mock

- Add CALLAI_ENDPOINT to the env module mock in useSimpleChat setup
- Resolves "Failed to generate title" warning in autoSelect test
- Ensures titleGenerator has all required config values during testing

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

Co-Authored-By: Claude <[email protected]>

* feat: add manual title flag to prevent AI title generation overrides

* test: add test suite for manual title preservation behavior

---------

Co-authored-by: CharlieHelps <[email protected]>
Co-authored-by: J Chris Anderson <[email protected]>
Co-authored-by: Claude <[email protected]>
* feat(netlify): add pre-mount nf_ab query-param cookie setter for Split Testing; docs for opt-in/opt-out and limitations

* fix(netlify split testing): externalize pre-mount nf_ab script; robust cookie parsing; refined reload + URL cleanup; document host-scoped cookie

* docs(split-testing): document only `ab=`; remove `?nf_ab` from user-facing docs

---------

Co-authored-by: CharlieHelps <[email protected]>
* feat(prompt): AI-powered LLMs.txt module selection using schema request; retain libs from history and integrate into system prompt

* fix(prompt): rebuild system prompt on every ensureSystemPrompt call\n\n- Remove early-return cache in useSystemPromptManager.ensureSystemPrompt\n- Always invoke makeBaseSystemPrompt with provided overrides (userPrompt/history)\n- Drop stale dependency on cached prompt in callback deps so state updates don’t gate rebuilds

* refactor(prompt): remove systemPrompt state/effect and return stateless ensureSystemPrompt\n\n- Drop useState/useEffect and all setSystemPrompt calls in useSystemPromptManager\n- ensureSystemPrompt always builds fresh prompt (or returns test string) and returns it\n- Hook now returns only the builder function; update useSimpleChat accordingly\n- Clean up unused imports and update JSDoc

* perf(prompts): precompile import-detection regexes and reuse in detectModulesInHistory\n\n- Build regex pairs once per llm entry (named + default import) at module scope\n- Refactor detectModulesInHistory to iterate precompiled descriptors\n- Preserve exact detection semantics; only removes per-call RegExp construction\n\nRefs: PR #202 review (r2265618388)

---------

Co-authored-by: CharlieHelps <[email protected]>
… blocks\n\n- Compute streaming-in-code via trailing fence detection and override Code control loading in header\n- Adjust ViewControls usage to reflect current streaming segment rather than code presence alone\n- Add tests simulating streaming code to assert indicator spins in-code and with multiple code segments\n\nCloses #220
@charliecreates charliecreates bot requested a review from CharlieHelps August 11, 2025 22:20
@netlify
Copy link

netlify bot commented Aug 11, 2025

Deploy Preview for fireproof-ai-builder ready!

Name Link
🔨 Latest commit b98e6c6
🔍 Latest deploy log https://app.netlify.com/projects/fireproof-ai-builder/deploys/689a6c9f9bd15700080ad131
😎 Deploy Preview https://deploy-preview-221--fireproof-ai-builder.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Contributor Author

@charliecreates charliecreates bot left a comment

Choose a reason for hiding this comment

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

  • Overriding viewControls.code with a fabricated fallback may unintentionally enable the Code control and alter its appearance when it was meant to be absent/disabled.
  • Tests dynamically re-mock dependencies without resetting the module cache, which can cause mocks to be ignored on subsequent imports and produce brittle results.
  • Consider adding a negative test to ensure the indicator stops spinning when the trailing code fence is closed (or when streaming stops) to fully lock in intended behavior.
Additional notes (1)
  • Maintainability | tests/code-indicator-streaming.test.tsx:157-210
    Test coverage only verifies the positive case (spins inside an open code fence). Consider adding a negative case to lock in behavior when the last fence is closed (or when isStreaming is false), ensuring the indicator does not spin.
Summary of changes
  • Added useMemo-based detection of whether the active AI stream is currently inside a Markdown code fence by counting occurrences of triple backticks in selectedResponseDoc.text and checking parity.
  • Introduced adjustedViewControls that overrides only the code control's loading state based on the new in-code detection, and wired it into the header via ResultPreviewHeaderContent.
  • Created new integration-style tests (tests/code-indicator-streaming.test.tsx) that mock the UI shell and simulate streaming with single and multiple code blocks to assert that the Code indicator spins when the trailing code fence is open.
  • Minor import change: added useMemo in home.tsx imports.

Comment on lines +118 to +128
const adjustedViewControls = useMemo(() => {
// Only override the code control; keep others intact
const codeControl = viewControls.code || { enabled: true, icon: 'code-icon', label: 'Code' };
return {
...viewControls,
code: {
...codeControl,
loading: isStreamingInCode,
},
};
}, [viewControls, isStreamingInCode]);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Creating a fallback code control when viewControls.code is falsy risks enabling the Code control in contexts where it was intentionally absent/disabled, and may also introduce an unexpected icon/label. To keep behavior identical outside of the streaming-in-code override, only modify the code control when it already exists and otherwise return viewControls unchanged.

Suggestion

Replace the adjustedViewControls block with a guard that only overrides when viewControls.code is present:

const adjustedViewControls = useMemo(() => {
  const code = viewControls.code;
  if (!code) return viewControls; // preserve absence/disabled state
  return {
    ...viewControls,
    code: {
      ...code,
      loading: isStreamingInCode,
    },
  };
}, [viewControls, isStreamingInCode]);

Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this change.

Comment on lines +158 to +160
beforeEach(() => {
// no-op
});
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Each test re-mocks useSimpleChat and then dynamically imports the module under test, but the module cache is never reset. This can cause the second test to reuse the previously cached ../app/routes/home module and ignore the updated mock, leading to brittle results dependent on import order. Reset the module graph between tests to ensure vi.doMock takes effect for each import.

Suggestion

Reset modules and clear mocks in beforeEach to ensure fresh imports per test:

beforeEach(() => {
  vi.resetModules();
  vi.clearAllMocks();
});

Alternatively, call vi.resetModules() immediately before each dynamic import('../app/routes/home').

Reply with "@CharlieHelps yes please" if you'd like me to add a commit with this change.

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.

code indicator should spin when ai response is streaming and in a code segment

5 participants