Skip to content

Conversation

@Danielsalamank
Copy link

Add complete Spanish translation for the Jan application including:

  • 15 translation files covering all app namespaces
  • Spanish language option in settings menu
  • Full UI translation support for Spanish-speaking users

All translation files created:

  • common.json (376 strings)
  • settings.json (312 strings)
  • chat.json, assistants.json, hub.json
  • providers.json, mcp-servers.json
  • system-monitor.json, tools.json
  • And 6 other translation files

Users can now select "Español" from the language switcher in Settings > General > Language to use the app in Spanish.

Describe Your Changes

Fixes Issues

  • Closes #
  • Closes #

Self Checklist

  • Added relevant comments, esp in complex areas
  • Updated docs (for bug fixes / features)
  • Created issues for follow-up changes or refactoring needed

Add complete Spanish translation for the Jan application including:
- 15 translation files covering all app namespaces
- Spanish language option in settings menu
- Full UI translation support for Spanish-speaking users

All translation files created:
- common.json (376 strings)
- settings.json (312 strings)
- chat.json, assistants.json, hub.json
- providers.json, mcp-servers.json
- system-monitor.json, tools.json
- And 6 other translation files

Users can now select "Español" from the language switcher
in Settings > General > Language to use the app in Spanish.
Copilot AI review requested due to automatic review settings November 4, 2025 19:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds Spanish (es) locale translations to the web application, enabling Spanish-speaking users to use the application in their native language. The translations cover all major UI components including settings, chat, assistants, providers, and system features.

  • Adds comprehensive Spanish translations across 15 JSON locale files
  • Registers Spanish language option in the LanguageSwitcher component
  • Maintains consistency with existing English locale structure

Reviewed Changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web-app/src/locales/es/updater.json Translation for app update notifications and actions
web-app/src/locales/es/tools.json Translation for tool approval dialogs and permissions
web-app/src/locales/es/tool-approval.json Translation for tool call request interface
web-app/src/locales/es/system-monitor.json Translation for system monitoring interface (CPU, GPU, memory)
web-app/src/locales/es/setup.json Translation for initial setup wizard
web-app/src/locales/es/settings.json Translation for all settings pages including interface, hardware, proxy, and privacy
web-app/src/locales/es/providers.json Translation for model provider management interface
web-app/src/locales/es/provider.json Translation for provider configuration
web-app/src/locales/es/model-errors.json Translation for model error messages
web-app/src/locales/es/mcp-servers.json Translation for MCP server configuration
web-app/src/locales/es/logs.json Translation for log viewer
web-app/src/locales/es/hub.json Translation for model hub interface
web-app/src/locales/es/common.json Translation for common UI elements and shared strings
web-app/src/locales/es/chat.json Translation for chat interface
web-app/src/locales/es/assistants.json Translation for assistant management
web-app/src/containers/LanguageSwitcher.tsx Adds Spanish language option to language selector

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"proxy": "Proxy",
"proxyUrl": "URL del Proxy",
"proxyUrlDesc": "La URL y puerto de tu servidor proxy.",
"proxyUrlPlaceholder": "http://proxy.ejemplo.com:8080",
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

[nitpick] Corrected spelling of 'ejemplo' to 'example' to maintain consistency with technical examples in other locales, or consider using a more generic placeholder like 'http://proxy.servidor.com:8080' to keep it fully Spanish.

Suggested change
"proxyUrlPlaceholder": "http://proxy.ejemplo.com:8080",
"proxyUrlPlaceholder": "http://proxy.example.com:8080",

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings November 4, 2025 21:19
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

"name": "@janhq/web-app",
"private": true,
"version": "0.6.6",
"version": "0.6.7",
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

Version mismatch detected: web-app/package.json specifies version 0.6.7 while src-tauri/tauri.conf.json specifies 0.6.600. These versions should be synchronized for consistency. Consider using 0.6.600 in both files or establishing a clear versioning strategy between the web app and Tauri app.

Suggested change
"version": "0.6.7",
"version": "0.6.600",

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
{
"noLogs": "No hay registros disponibles"
}
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The Spanish logs.json file has 4 lines (including braces and whitespace) while the English version has 3 lines. This is a minor formatting inconsistency - both files should use the same JSON formatting for maintainability.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +6
{
"welcome": "Bienvenido a Jan",
"description": "Para comenzar, necesitarás descargar un modelo de IA local o conectarte a un modelo en la nube usando una clave API",
"localModel": "Configurar modelo local",
"remoteProvider": "Configurar proveedor remoto"
}
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The Spanish setup.json has 6 lines while the English version has 6 lines, but close inspection shows the Spanish version has an extra line. Both files should have the same number of lines for consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to +4
"addProvider": "Agregar Proveedor",
"addOpenAIProvider": "Agregar Proveedor OpenAI",
"enterNameForProvider": "Ingresa nombre para proveedor"
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

The Spanish provider.json file has 5 lines while the English version has 5 lines. However, there appears to be duplicate content between provider.json and providers.json (lines 72-74). Consider whether provider.json is still needed or if it should be deprecated to avoid maintaining duplicate translation strings.

Suggested change
"addProvider": "Agregar Proveedor",
"addOpenAIProvider": "Agregar Proveedor OpenAI",
"enterNameForProvider": "Ingresa nombre para proveedor"
// DEPRECATED: All translation strings have been moved to providers.json. This file is no longer maintained.

Copilot uses AI. Check for mistakes.
Comment on lines +306 to +309
"updateError": "Error al actualizar Llamacpp"
},
"backendInstallSuccess": "Backend instalado exitosamente",
"backendInstallError": "Error al instalar backend"
Copy link

Copilot AI Nov 4, 2025

Choose a reason for hiding this comment

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

Lines 308-309 are at the root level of the JSON object, outside of any nested structure, while most other settings are organized into nested objects (e.g., 'hardware', 'httpsProxy', 'localApiServer'). Verify that these strings should be at root level or if they belong in a specific section for better organization.

Suggested change
"updateError": "Error al actualizar Llamacpp"
},
"backendInstallSuccess": "Backend instalado exitosamente",
"backendInstallError": "Error al instalar backend"
"updateError": "Error al actualizar Llamacpp",
"backendInstallSuccess": "Backend instalado exitosamente",
"backendInstallError": "Error al instalar backend"
}

Copilot uses AI. Check for mistakes.
Integrate custom Whisper API for voice-to-text transcription in Jan chat.

New Features:
- Voice input button in chat interface with recording UI
- Real-time audio recording from microphone
- Configurable Whisper API integration (supports custom endpoints)
- Settings page for API configuration and testing
- Multi-language support with auto-detection
- Recording controls (pause, resume, cancel)

Components Added:
- useAudioRecorder hook: Browser audio recording with MediaRecorder API
- whisper service: API client for transcription
- MicrophoneButton: Interactive recording UI with modal dialog
- Whisper settings page: Configuration and testing interface

Technical Details:
- WebM audio format with Opus codec at 16kHz (Whisper optimized)
- localStorage for API credentials
- 25MB file size limit
- Cross-browser compatible (Chrome, Firefox, Safari, Edge)

Configuration:
- Navigate to Settings > Whisper
- Enter API URL: https://whisper.contextcompany.com.co/v1/audio/transcriptions
- Add API key and optional model/language settings
- Test connection before use

Usage:
1. Click microphone icon in chat input
2. Speak message
3. Click check to transcribe
4. Text automatically inserted into chat input

Documentation:
- WHISPER_INTEGRATION.md: Complete integration guide
- WHISPER_QUICKSTART.md: Quick start instructions

Closes requirement for voice input functionality
…ebservice spec

Updated Whisper integration to use the correct API specification:
- Changed endpoint from /v1/audio/transcriptions to /asr
- Changed FormData field from 'file' to 'audio_file'
- Replaced 'model' parameter with 'task', 'output', 'encode', 'vadFilter', 'wordTimestamps'
- Made API key optional (not all servers require it)
- Updated settings page with new parameter controls (task selector, output format, VAD filter, word timestamps)
- Updated documentation (WHISPER_INTEGRATION.md, WHISPER_QUICKSTART.md) to reflect correct API usage

This matches the actual API specification provided by the user for their Whisper ASR Webservice.
Copilot AI review requested due to automatic review settings November 10, 2025 02:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 32 out of 32 changed files in this pull request and generated 13 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 85 to 108
const handleTest = async () => {
try {
setIsTesting(true)

if (!config.apiUrl) {
toast.error('Please configure API URL first')
return
}

// Start recording
toast.info('Recording audio... Click again to stop', { id: 'test-recording' })
await startRecording()

// Wait for user to stop
// Note: This is a simplified test flow
} catch (error) {
console.error('Test failed:', error)
toast.error('Test failed', {
description: error instanceof Error ? error.message : 'Unknown error',
})
} finally {
setIsTesting(false)
}
}
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The test flow implementation is incomplete and confusing. The handleTest function starts recording but doesn't wait for the user to stop it properly. The function immediately returns after calling startRecording(), setting isTesting to false in the finally block before the recording actually stops. This creates a race condition where isTesting might be false when the user tries to stop recording.

The comment on line 99 says "Wait for user to stop" but there's no actual waiting mechanism. Consider implementing a proper state machine for the test flow.

Copilot uses AI. Check for mistakes.

// Default configuration - users should update this
return {
apiUrl: 'https://whisper.contextcompany.com.co/asr',
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Hardcoded API URL in the default configuration. The default Whisper config includes a specific company URL (https://whisper.contextcompany.com.co/asr) which appears to be a private/company-specific endpoint. This should either be left empty by default or use a more generic placeholder to avoid confusion and potential misuse of someone else's API endpoint.

Consider using an empty string or a clear placeholder like https://your-whisper-api-url.com/asr.

Copilot uses AI. Check for mistakes.
Comment on lines 67 to 70
if (!config.apiUrl) {
toast.error('API URL is required')
return
}
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Missing input validation for API URL in the save handler. While there's a check that the URL is not empty, there's no validation that it's a valid URL format. This could lead to runtime errors when attempting to make the API request.

Consider adding URL validation (e.g., using new URL() and catching errors) before saving.

Copilot uses AI. Check for mistakes.
Comment on lines 84 to 90
if (!config.apiKey) {
toast.error('Whisper API key not configured', {
description: 'Please configure your Whisper API key in settings.',
})
return
}

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The API key validation check will prevent users from using the voice input feature even when the API key is optional. The check at line 84 requires config.apiKey to be present, but according to the interface and settings page, the API key is optional. This will cause the transcription to fail with an error message saying "Whisper API key not configured" even when the server doesn't require authentication.

Consider removing this check or making it conditional based on the server's authentication requirements.

Suggested change
if (!config.apiKey) {
toast.error('Whisper API key not configured', {
description: 'Please configure your Whisper API key in settings.',
})
return
}
// Proceed even if config.apiKey is not set; backend will handle auth if required

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +142
return new Promise((resolve) => {
const mediaRecorder = mediaRecorderRef.current!

mediaRecorder.onstop = () => {
const mimeType = mediaRecorder.mimeType
const blob = new Blob(chunksRef.current, { type: mimeType })

// Stop timer
if (timerRef.current) {
clearInterval(timerRef.current)
timerRef.current = null
}

// Stop all tracks
if (streamRef.current) {
streamRef.current.getTracks().forEach(track => track.stop())
streamRef.current = null
}

setState((prev) => ({
...prev,
audioBlob: blob,
isRecording: false,
isPaused: false,
}))

resolve(blob)
}

mediaRecorder.stop()
})
}
return null
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The error handling in stopRecording has a potential issue. When recording is stopped and the promise is resolved, if there's an error in the onstop handler, the promise will never reject or resolve, potentially leaving the caller hanging. Additionally, the function returns null when state.isRecording is false, but the return type is Promise<Blob | null>, which means callers need to handle the null case even when they expect a Blob.

Consider adding error handling within the promise and ensuring the state is properly managed.

Suggested change
return new Promise((resolve) => {
const mediaRecorder = mediaRecorderRef.current!
mediaRecorder.onstop = () => {
const mimeType = mediaRecorder.mimeType
const blob = new Blob(chunksRef.current, { type: mimeType })
// Stop timer
if (timerRef.current) {
clearInterval(timerRef.current)
timerRef.current = null
}
// Stop all tracks
if (streamRef.current) {
streamRef.current.getTracks().forEach(track => track.stop())
streamRef.current = null
}
setState((prev) => ({
...prev,
audioBlob: blob,
isRecording: false,
isPaused: false,
}))
resolve(blob)
}
mediaRecorder.stop()
})
}
return null
return new Promise<Blob | null>((resolve, reject) => {
const mediaRecorder = mediaRecorderRef.current!
// Handler cleanup helper
const cleanup = () => {
mediaRecorder.onstop = null
mediaRecorder.onerror = null
}
mediaRecorder.onstop = () => {
try {
const mimeType = mediaRecorder.mimeType
const blob = new Blob(chunksRef.current, { type: mimeType })
// Stop timer
if (timerRef.current) {
clearInterval(timerRef.current)
timerRef.current = null
}
// Stop all tracks
if (streamRef.current) {
streamRef.current.getTracks().forEach(track => track.stop())
streamRef.current = null
}
setState((prev) => ({
...prev,
audioBlob: blob,
isRecording: false,
isPaused: false,
}))
resolve(blob)
} catch (err: any) {
setState((prev) => ({
...prev,
error: err?.message || 'Failed to process audio recording.',
isRecording: false,
isPaused: false,
}))
reject(err)
} finally {
cleanup()
}
}
mediaRecorder.onerror = (event: any) => {
setState((prev) => ({
...prev,
error: event?.error?.message || 'Recording error occurred.',
isRecording: false,
isPaused: false,
}))
cleanup()
reject(event?.error || new Error('Recording error occurred.'))
}
try {
mediaRecorder.stop()
} catch (err: any) {
cleanup()
setState((prev) => ({
...prev,
error: err?.message || 'Failed to stop recording.',
isRecording: false,
isPaused: false,
}))
reject(err)
}
})
}
// Always return a Promise
return Promise.resolve(null)

Copilot uses AI. Check for mistakes.
Comment on lines +55 to +65
const handleMicrophoneClick = async () => {
if (disabled) return

if (!state.isRecording) {
// Start recording
await startRecording()
} else {
// Stop recording and transcribe
await handleStopAndTranscribe()
}
}
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Race condition in the recording state management. When the user clicks the microphone button while recording (state.isRecording is true), it calls handleStopAndTranscribe. However, if the user rapidly clicks the button, multiple calls to stopRecording could occur before the first one completes, leading to unexpected behavior.

Consider adding a loading/processing state check to prevent concurrent operations.

Copilot uses AI. Check for mistakes.
"securityNotice": "Herramientas maliciosas o contenido de conversación podrían potencialmente engañar al asistente para intentar acciones dañinas. Revisa cada llamada de herramienta cuidadosamente antes de aprobar.",
"deny": "Denegar",
"allowOnce": "Permitir Una Vez",
"alwaysAllow": "Permitir en hilo",
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The translation "Permitir en hilo" for "alwaysAllow" is awkward and potentially confusing in Spanish. The phrase "en hilo" literally means "in thread" but doesn't convey the intended meaning of "always allow" or "allow for this conversation". A better translation would be "Permitir siempre" (Allow always) or "Permitir para este hilo" (Allow for this thread) to make the meaning clearer.

Consider using "Permitir siempre" for better clarity.

Suggested change
"alwaysAllow": "Permitir en hilo",
"alwaysAllow": "Permitir siempre",

Copilot uses AI. Check for mistakes.
"securityNotice": "<strong>Aviso de Seguridad:</strong> Herramientas maliciosas o contenido de conversación podrían potencialmente engañar al asistente para intentar acciones dañinas. Revisa cada llamada de herramienta cuidadosamente antes de aprobar.",
"deny": "Denegar",
"allowOnce": "Permitir Una Vez",
"alwaysAllow": "Permitir en hilo",
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Same translation issue as in tools.json. The translation "Permitir en hilo" for "alwaysAllow" should be "Permitir siempre" for consistency and better clarity throughout the application.

Suggested change
"alwaysAllow": "Permitir en hilo",
"alwaysAllow": "Permitir siempre",

Copilot uses AI. Check for mistakes.
Comment on lines 111 to 133
useEffect(() => {
const handleTestTranscription = async () => {
if (isTesting && !recorderState.isRecording && recorderState.audioBlob) {
try {
toast.loading('Testing transcription...', { id: 'test-transcription' })

const result = await transcribeAudio(recorderState.audioBlob, config)

toast.success('Test successful!', {
id: 'test-transcription',
description: `Transcribed: "${result.text.substring(0, 100)}..."`,
})
} catch (error) {
toast.error('Test failed', {
id: 'test-transcription',
description: error instanceof Error ? error.message : 'Unknown error',
})
}
}
}

handleTestTranscription()
}, [recorderState.isRecording, recorderState.audioBlob, isTesting, config])
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The useEffect hook has a dependency issue. The effect depends on config which is a complex object that changes on every render when the state is updated. This will cause the effect to run repeatedly and potentially trigger multiple transcription attempts. The dependency array should include only the primitive values that actually affect the transcription logic, or the effect should use a ref to track whether transcription has already been initiated.

Consider using useRef to track transcription status or restructure the dependencies to avoid infinite loops.

Copilot uses AI. Check for mistakes.
const [isTesting, setIsTesting] = useState(false)
const [showApiKey, setShowApiKey] = useState(false)

const { startRecording, stopRecording, state: recorderState } = useAudioRecorder()
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Unused variable stopRecording.

Copilot uses AI. Check for mistakes.
Danielsalamank and others added 4 commits November 10, 2025 03:19
…-011CUoMCCPrvSfShzYwnntZi

Claude/add spanish language 011 c uo mcc prv sf shz ywnnt zi
…page

refactor(chat): improve streaming content check in ChatInput
refactor(card): make separator optional in CardItem
chore(deps): update tauri plugin opener and token.js
chore(config): add workspace package alias in vite config
feat(routing): add whisper settings route
chore(extensions): add rag and vector db extensions
The Whisper server at whisper.contextcompany.com.co does not require
authentication, so API Key field has been completely removed:

- Removed apiKey from WhisperConfig interface
- Removed API Key field from settings UI (whisper.tsx)
- Removed Authorization header from API requests
- Updated documentation to reflect no authentication needed
- Updated WHISPER_INTEGRATION.md and WHISPER_QUICKSTART.md

This matches the actual n8n configuration provided by the user, which
shows no authentication headers are sent to the /asr endpoint.
Added GPU_SETUP.md with detailed instructions for:
- NVIDIA driver installation on Ubuntu/Debian
- Diagnosing GPU detection issues
- Docker GPU access configuration
- Jan-specific GPU settings (device offload, backend selection)
- Troubleshooting common GPU problems
- Performance benchmarks

This addresses the common issue where Jan runs on CPU instead of GPU
due to missing drivers or Docker isolation.

Includes specific guidance for RTX 5090 and other high-end GPUs.
Copilot AI review requested due to automatic review settings November 10, 2025 05:20
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 38 out of 41 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 84 to 90
if (!config.apiKey) {
toast.error('Whisper API key not configured', {
description: 'Please configure your Whisper API key in settings.',
})
return
}

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The code checks for config.apiKey but the WhisperConfig interface in whisper.ts doesn't include an apiKey property. According to the documentation and settings page, the Whisper API doesn't require authentication. This check should be removed or changed to check config.apiUrl instead.

Suggested change
if (!config.apiKey) {
toast.error('Whisper API key not configured', {
description: 'Please configure your Whisper API key in settings.',
})
return
}

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +16
function Checkbox({ className, ...props }: CheckboxProps) {
return (
<input
type="checkbox"
data-slot="checkbox"
className={cn(
'size-4 rounded-sm border border-main-view-fg/20 bg-transparent checked:bg-accent checked:border-accent focus-visible:outline-none focus-visible:ring-ring/40 focus-visible:ring-[2px] disabled:opacity-50 disabled:cursor-not-allowed',
className
)}
{...props}
/>
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The checkbox component uses a native <input type='checkbox'> but doesn't have proper visual indication for the checked state beyond colors. Consider adding a checkmark icon or ensure the checked:bg-accent provides sufficient contrast for users with visual impairments.

Suggested change
function Checkbox({ className, ...props }: CheckboxProps) {
return (
<input
type="checkbox"
data-slot="checkbox"
className={cn(
'size-4 rounded-sm border border-main-view-fg/20 bg-transparent checked:bg-accent checked:border-accent focus-visible:outline-none focus-visible:ring-ring/40 focus-visible:ring-[2px] disabled:opacity-50 disabled:cursor-not-allowed',
className
)}
{...props}
/>
function Checkbox({ className, checked, defaultChecked, onChange, ...props }: CheckboxProps) {
const [internalChecked, setInternalChecked] = React.useState(defaultChecked ?? false);
const isControlled = checked !== undefined;
const isChecked = isControlled ? checked : internalChecked;
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (!isControlled) {
setInternalChecked(e.target.checked);
}
if (onChange) {
onChange(e);
}
};
return (
<span className="relative inline-block align-middle">
<input
type="checkbox"
data-slot="checkbox"
className={cn(
'size-4 rounded-sm border border-main-view-fg/20 bg-transparent checked:bg-accent checked:border-accent focus-visible:outline-none focus-visible:ring-ring/40 focus-visible:ring-[2px] disabled:opacity-50 disabled:cursor-not-allowed',
className
)}
checked={checked}
defaultChecked={defaultChecked}
onChange={handleChange}
aria-checked={isChecked}
{...props}
/>
{isChecked && (
<svg
className="pointer-events-none absolute left-1/2 top-1/2 h-3 w-3 -translate-x-1/2 -translate-y-1/2 text-white"
viewBox="0 0 16 16"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<polyline points="4 8.5 7 11.5 12 5.5" />
</svg>
)}
</span>

Copilot uses AI. Check for mistakes.
Comment on lines +242 to +244
onChange={(e) =>
setConfig((prev) => ({ ...prev, vadFilter: e.currentTarget.checked }))
}
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

[nitpick] The Checkbox component uses onChange but standard HTML checkboxes use onChange with e.target.checked, not e.currentTarget.checked. While currentTarget works, target is more conventional and consistent with React patterns.

Copilot uses AI. Check for mistakes.
Danielsalamank and others added 8 commits November 10, 2025 05:28
…-011CUoMCCPrvSfShzYwnntZi

Claude/add spanish language 011 c uo mcc prv sf shz ywnnt zi
…support after merge

After merging dev branch, some features were lost:
- Spanish (es), French (fr), and Russian (ru) languages removed from LanguageSwitcher
- Whisper route removed from routes.ts
- Whisper menu item removed from SettingsMenu
- MicrophoneButton removed from ChatInput

This commit restores all features:
1. Added es, fr, ru back to LANGUAGES array in LanguageSwitcher
2. Added whisper route to routes.ts settings object
3. Added Whisper menu item to SettingsMenu
4. Re-imported and re-added MicrophoneButton to ChatInput with transcription handling

All Whisper service files, settings page, and locale files remain intact.
…-011CUoMCCPrvSfShzYwnntZi

fix: restore Whisper integration and Spanish/French/Russian language …
- Add new extension types RAG and VectorDB to ExtensionTypeEnum
- Implement new tauri plugins for RAG and VectorDB functionality
- Update extension exports to include new RAG and VectorDB types
- Add new settings routes for attachments and interface configuration
Add conditional fetch implementation that uses Tauri's HTTP plugin when running in a Tauri environment to avoid CORS restrictions while maintaining browser compatibility
Problem:
Browser was blocking Whisper API requests from localhost:1420 to
whisper.contextcompany.com.co due to missing CORS headers:
"Access-Control-Allow-Origin header is not present on the requested resource"

Solution:
1. Created new Tauri command `http_post_multipart` in src-tauri/src/core/http/
   - Makes HTTP POST requests with multipart/form-data from backend
   - Bypasses CORS restrictions entirely (backend-to-server communication)
   - Supports query parameters, file uploads, and custom headers

2. Updated Whisper service (web-app/src/services/whisper/whisper.ts):
   - Now uses Tauri invoke() to call backend command
   - Converts audio Blob to Uint8Array for Rust interop
   - Removed apiKey field (not needed for this Whisper server)
   - Maintains same API contract for frontend components

Technical details:
- Uses reqwest crate for HTTP client (already in dependencies)
- Supports 5-minute timeout for long transcriptions
- Properly handles both JSON and plain text responses
- Error handling with detailed status codes

This matches the working n8n configuration which also makes server-side
requests (no CORS issues in Node.js backend).
Copilot AI review requested due to automatic review settings November 10, 2025 08:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 245 out of 540 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 12 to 21
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'ru', label: 'Русский' },
{ value: 'id', label: 'Bahasa' },
{ value: 'pl', label: 'Polski' },
{ value: 'vn', label: 'Tiếng Việt' },
{ value: 'zh-CN', label: '简体中文' },
{ value: 'zh-TW', label: '繁體中文' },
{ value: 'de-DE', label: 'Deutsch' },
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The PR description claims to add Spanish language support, but this diff shows Spanish ('es'), French ('fr'), and Russian ('ru') being added while removing Portuguese ('pt-BR') and Japanese ('ja'). The PR title and description only mention Spanish, which is misleading.

Copilot uses AI. Check for mistakes.

// Build the client
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(300)) // 5 minutes timeout
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

[nitpick] The comment states '5 minutes timeout' but the code specifies 300 seconds which is also 5 minutes. However, this should be clarified as the constant name suggests it might be configurable, but it's hardcoded here.

Copilot uses AI. Check for mistakes.
if (isEmbedding) {
args.push('--embedding')
args.push('--pooling', 'mean')
args.push('--pooling mean')
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The '--pooling mean' argument should be passed as two separate array elements ['--pooling', 'mean'], not as a single string '--pooling mean'. This will likely cause the argument to be improperly parsed by the command line.

Suggested change
args.push('--pooling mean')
args.push('--pooling', 'mean')

Copilot uses AI. Check for mistakes.
jan-utils = { path = "./utils" }
libloading = "0.8.7"
log = "0.4"
reqwest = { version = "0.11", features = ["json", "blocking", "stream"] }
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The reqwest dependency is now declared at the workspace level without TLS backend specification. This may cause build issues on some platforms as neither 'native-tls' nor 'rustls-tls' features are explicitly enabled.

Suggested change
reqwest = { version = "0.11", features = ["json", "blocking", "stream"] }
reqwest = { version = "0.11", features = ["json", "blocking", "stream", "rustls-tls"] }

Copilot uses AI. Check for mistakes.
…om command

Resolved merge conflict by adopting dev's cleaner approach:
- Uses @tauri-apps/plugin-http (fetchTauri) instead of custom Rust command
- Removed custom src-tauri/src/core/http module (no longer needed)
- Reverted changes to lib.rs and core/mod.rs
- Tauri HTTP plugin handles CORS automatically and is more maintainable

Benefits:
- Less code to maintain
- Uses official Tauri plugin
- Same CORS bypass functionality
- Better TypeScript/Rust interop (no serialization needed)
…support after merge

This commit fixes the persistent CORS error when using Whisper voice transcription by implementing a reliable backend HTTP solution.

Changes:
- Created custom Tauri HTTP module (src-tauri/src/core/http/) with http_post_multipart command
- Updated whisper.ts to use invoke() with custom Rust command instead of fetchTauri
- Converts audio Blob to Uint8Array for Rust interop
- Makes HTTP requests from Rust backend, bypassing browser CORS restrictions
- Registered http_post_multipart command in Tauri invoke_handler

This approach is more reliable than the plugin-http fetchTauri conditional detection, which was falling back to browser fetch and triggering CORS errors.
Copilot AI review requested due to automatic review settings November 10, 2025 08:55
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 245 out of 540 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


const LANGUAGES = [
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Spanish language option added but no translation files are present in the diff. The PR description claims '15 translation files' were added, but they are not included in this changeset. This will cause runtime errors when users select Spanish.

Suggested change
{ value: 'es', label: 'Español' },
// { value: 'es', label: 'Español' }, // Disabled until translation files are present

Copilot uses AI. Check for mistakes.
Comment on lines +4 to 9
pub const MCP_TOOL_CALL_TIMEOUT: Duration = Duration::from_secs(30);
pub const MCP_BASE_RESTART_DELAY_MS: u64 = 1000; // Start with 1 second
pub const MCP_MAX_RESTART_DELAY_MS: u64 = 30000; // Cap at 30 seconds
pub const MCP_BACKOFF_MULTIPLIER: f64 = 2.0; // Double the delay each time

pub const DEFAULT_MCP_CONFIG: &str = r#"{
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The constant was changed from a configurable value to a hardcoded 30-second timeout. This removes the ability for users to configure timeout values through the UI, which could cause issues for slower tool calls.

Suggested change
pub const MCP_TOOL_CALL_TIMEOUT: Duration = Duration::from_secs(30);
pub const MCP_BASE_RESTART_DELAY_MS: u64 = 1000; // Start with 1 second
pub const MCP_MAX_RESTART_DELAY_MS: u64 = 30000; // Cap at 30 seconds
pub const MCP_BACKOFF_MULTIPLIER: f64 = 2.0; // Double the delay each time
pub const DEFAULT_MCP_CONFIG: &str = r#"{
// pub const MCP_TOOL_CALL_TIMEOUT: Duration = Duration::from_secs(30);
pub const MCP_BASE_RESTART_DELAY_MS: u64 = 1000; // Start with 1 second
pub const MCP_MAX_RESTART_DELAY_MS: u64 = 30000; // Cap at 30 seconds
pub const MCP_BACKOFF_MULTIPLIER: f64 = 2.0; // Double the delay each time
pub const DEFAULT_MCP_CONFIG: &str = r#"{
"toolCallTimeoutSecs": 30,

Copilot uses AI. Check for mistakes.
const hasActiveMCPServers = connectedServers.length > 0 || tools.length > 0

const handleSendMessage = async (prompt: string) => {
const handleSendMesage = (prompt: string) => {
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Corrected spelling of 'Mesage' to 'Message'.

Suggested change
const handleSendMesage = (prompt: string) => {
const handleSendMessage = (prompt: string) => {

Copilot uses AI. Check for mistakes.
field_name: String,
headers: Option<HashMap<String, String>>,
) -> Result<HttpResponse, String> {
log::info!("Making HTTP POST multipart request to: {}", url);
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

URL is logged without sanitization. If the URL contains sensitive information (like API keys in query parameters), this could leak secrets into log files.

Copilot uses AI. Check for mistakes.
"@jan/extensions-web": "workspace:*",
"@janhq/core": "workspace:*",
"@jan/extensions-web": "link:../extensions-web",
"@janhq/core": "link:../core",
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Changed from workspace protocol to link protocol. This can cause issues in monorepo setups and prevents proper dependency resolution. Should use workspace:* instead of link: for better compatibility.

Suggested change
"@janhq/core": "link:../core",
"@janhq/core": "workspace:*",

Copilot uses AI. Check for mistakes.
{ "value": "on", "name": "On" },
{ "value": "off", "name": "Off" }
]
"value": false
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Flash Attention default changed from 'auto' to disabled (false). This could significantly impact performance as Flash Attention auto-detection is generally optimal for supported hardware.

Suggested change
"value": false
"value": "auto"

Copilot uses AI. Check for mistakes.
pub async fn load_llama_model<R: Runtime>(
app_handle: tauri::AppHandle<R>,
backend_path: &str,
library_path: Option<&str>,
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

New required parameter library_path added to public API without deprecation period. This is a breaking change that will cause compilation errors for existing code calling this function.

Copilot uses AI. Check for mistakes.
- Added "multipart" feature to reqwest dependency in Cargo.toml
- Changed http commands module from private to public
- Fixes compilation errors for http_post_multipart command
- Log audio blob information (size, type, length)
- Log query parameters being sent
- Log full response from Whisper API
- Help diagnose transcription quality issues
Copilot AI review requested due to automatic review settings November 10, 2025 09:15
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 245 out of 540 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

{ value: 'vn', label: 'Tiếng Việt' },
{ value: 'zh-CN', label: '简体中文' },
{ value: 'zh-TW', label: '繁體中文' },
{ value: 'de-DE', label: 'Deutsch' },
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Languages removed from this array (pt-BR and ja) should be verified - if their translation files still exist in the codebase, they should either be restored here or the translation files should be removed to maintain consistency.

Suggested change
{ value: 'de-DE', label: 'Deutsch' },
{ value: 'de-DE', label: 'Deutsch' },
{ value: 'pt-BR', label: 'Português (Brasil)' },
{ value: 'ja', label: '日本語' },

Copilot uses AI. Check for mistakes.
Comment on lines 631 to +634
let mut cache_dir = app_path.clone();
cache_dir.push(".npx");
cmd = Command::new(bun_x_path.display().to_string());
let bun_x_path = format!("{}/bun", bin_path.display());
cmd = Command::new(bun_x_path);
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The can_override_npx() function no longer validates the existence of the bun binary path (this validation was removed in src-tauri/utils/src/system.rs). This could cause runtime errors if the bun binary doesn't exist at the expected location. Consider adding path existence validation before constructing the command.

Copilot uses AI. Check for mistakes.

if (platform === 'darwin') {
bunPlatform = arch === 'arm64' ? 'darwin-aarch64' : 'darwin-x64'
bunPlatform = arch === 'arm64' ? 'darwin-aarch64' : 'darwin-x86'
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The platform string for macOS x64 should be 'darwin-x64' (or 'darwin-x86_64'), not 'darwin-x86'. This will likely cause download failures for Intel-based Macs.

Suggested change
bunPlatform = arch === 'arm64' ? 'darwin-aarch64' : 'darwin-x86'
bunPlatform = arch === 'arm64' ? 'darwin-aarch64' : 'darwin-x64'

Copilot uses AI. Check for mistakes.
log::info!("Using arguments: {:?}", args);

let bin_path = validate_binary_path(backend_path)?;
validate_binary_path(backend_path)?;
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

[nitpick] The validated PathBuf from validate_binary_path is no longer being used (previously assigned to bin_path). While the validation still occurs, consider whether this validation is necessary if the result is discarded, or if the function should be refactored to make its purpose clearer.

Copilot uses AI. Check for mistakes.
if (cfg.split_mode.length > 0 && cfg.split_mode != 'layer')
args.push('--split-mode', cfg.split_mode)
if (cfg.main_gpu !== undefined && cfg.main_gpu !== 0)
if (cfg.main_gpu !== undefined && cfg.main_gpu != 0)
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Use strict equality operator !== instead of loose equality != for type-safe comparison.

Suggested change
if (cfg.main_gpu !== undefined && cfg.main_gpu != 0)
if (cfg.main_gpu !== undefined && cfg.main_gpu !== 0)

Copilot uses AI. Check for mistakes.
- Changed default language from 'auto' to 'es' in getDefaultWhisperConfig()
- Auto-detection was causing incorrect transcriptions (detecting as Norwegian instead of Spanish)
- Users can still change language in Whisper settings or use 'auto' if needed
- Import i18n to access Jan's current language setting
- getDefaultWhisperConfig() now uses i18n.language instead of hardcoded 'es'
- Whisper will automatically transcribe in the language Jan is configured to use
- If Jan is in Spanish, Whisper uses 'es'; if English, uses 'en'; etc.
- Falls back to 'en' if language is not detected
Copilot AI review requested due to automatic review settings November 10, 2025 09:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 245 out of 540 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (1)

src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rs:1

  • The API signature has changed significantly by removing is_embedding and timeout parameters. This is a breaking change for any external code calling this function. The timeout is now hardcoded to 300 seconds, removing flexibility for users with slower systems or larger models that need more time to load.
use base64::{engine::general_purpose, Engine as _};

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 12 to 21
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'ru', label: 'Русский' },
{ value: 'id', label: 'Bahasa' },
{ value: 'pl', label: 'Polski' },
{ value: 'vn', label: 'Tiếng Việt' },
{ value: 'zh-CN', label: '简体中文' },
{ value: 'zh-TW', label: '繁體中文' },
{ value: 'de-DE', label: 'Deutsch' },
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Languages have been reordered and some removed (pt-BR, ja) while adding new ones (es, fr). This reordering makes the language list less consistent. Consider maintaining alphabetical order or grouping by language family for better maintainability. Also verify that translation files exist for all newly added languages (es, fr).

Suggested change
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'ru', label: 'Русский' },
{ value: 'id', label: 'Bahasa' },
{ value: 'pl', label: 'Polski' },
{ value: 'vn', label: 'Tiếng Việt' },
{ value: 'zh-CN', label: '简体中文' },
{ value: 'zh-TW', label: '繁體中文' },
{ value: 'de-DE', label: 'Deutsch' },
{ value: 'id', label: 'Bahasa' },
{ value: 'de-DE', label: 'Deutsch' },
{ value: 'en', label: 'English' },
{ value: 'es', label: 'Español' },
{ value: 'fr', label: 'Français' },
{ value: 'pl', label: 'Polski' },
{ value: 'ru', label: 'Русский' },
{ value: 'vn', label: 'Tiếng Việt' },
{ value: 'zh-CN', label: '简体中文' },
{ value: 'zh-TW', label: '繁體中文' },

Copilot uses AI. Check for mistakes.
Comment on lines 18 to 20
/// Tool with server information
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolWithServer {
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The entire McpSettings struct and related functionality have been removed, which means MCP timeout and restart behavior are now hardcoded in constants. This reduces configurability and makes it impossible for users to adjust these values without recompiling. Consider keeping the settings structure but with default values if runtime configuration is not needed.

Copilot uses AI. Check for mistakes.
Comment on lines 89 to +100
const [message, setMessage] = useState('')
const [dropdownToolsAvailable, setDropdownToolsAvailable] = useState(false)
const [tooltipToolsAvailable, setTooltipToolsAvailable] = useState(false)
const [attachments, setAttachments] = useState<Attachment[]>([])
const [uploadedFiles, setUploadedFiles] = useState<
Array<{
name: string
type: string
size: number
base64: string
dataUrl: string
}>
>([])
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The attachment handling has been drastically simplified, removing RAG document ingestion, validation, processing states, and duplicate checking. This removes significant functionality around document attachments. The new implementation only supports basic image uploads without the previous robust error handling and user feedback mechanisms.

Copilot uses AI. Check for mistakes.
)]
use crate::core::setup::setup_tray;

#[cfg_attr(mobile, tauri::mobile_entry_point)]
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Mobile platform support has been removed throughout the codebase (Android and iOS feature flags, conditional compilation, etc.). This is a major architectural change that should be clearly documented in the PR description and communicated to users who may be relying on mobile builds.

Suggested change
#[cfg_attr(mobile, tauri::mobile_entry_point)]

Copilot uses AI. Check for mistakes.
Comment on lines 28 to +31
"dev:tauri": "yarn build:icon && yarn copy:assets:tauri && cross-env IS_CLEAN=true tauri dev",
"dev:ios": "yarn copy:assets:mobile && RUSTC_WRAPPER= cross-env IS_IOS=true yarn tauri ios dev --features mobile",
"dev:android": "yarn copy:assets:mobile && cross-env IS_ANDROID=true yarn tauri android dev --features mobile",
"build:android": "yarn build:icon && yarn copy:assets:mobile && cross-env IS_CLEAN=true yarn tauri android build -- --no-default-features --features mobile",
"build:ios": "yarn build:icon && yarn copy:assets:mobile && cross-env IS_IOS=true yarn tauri ios build -- --no-default-features --features mobile",
"build:ios:device": "yarn build:icon && yarn copy:assets:mobile && cross-env IS_IOS=true yarn tauri ios build -- --no-default-features --features mobile --export-method debugging",
"copy:assets:tauri": "cpx \"pre-install/*.tgz\" \"src-tauri/resources/pre-install/\" && cpx \"LICENSE\" \"src-tauri/resources/\"",
"copy:assets:mobile": "cpx \"pre-install/*.tgz\" \"src-tauri/resources/pre-install/\" && cpx \"LICENSE\" \"src-tauri/resources/\"",
"download:lib": "node ./scripts/download-lib.mjs",
"download:bin": "node ./scripts/download-bin.mjs",
"build:tauri:win32": "yarn download:bin && yarn tauri build",
"build:tauri:linux": "yarn download:bin && NO_STRIP=1 ./src-tauri/build-utils/shim-linuxdeploy.sh yarn tauri build && ./src-tauri/build-utils/buildAppImage.sh",
"build:tauri:win32": "yarn download:bin && yarn download:lib && yarn tauri build",
"build:tauri:linux": "yarn download:bin && yarn download:lib && NO_STRIP=1 ./src-tauri/build-utils/shim-linuxdeploy.sh yarn tauri build && ./src-tauri/build-utils/buildAppImage.sh",
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Mobile build scripts (ios, android, dev:ios, dev:android, build:android, build:ios) have been completely removed. This represents a significant reduction in platform support and should be documented as a breaking change.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +15
pub static MESSAGE_LOCKS: Lazy<Mutex<HashMap<String, Arc<Mutex<()>>>>> =
Lazy::new(|| Mutex::new(HashMap::new()));
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Changed from OnceLock to Lazy from once_cell crate. While functionally similar, this introduces a new dependency (once_cell) and changes the initialization pattern. Consider documenting why this change was necessary or revert to using OnceLock from std if targeting Rust 1.70+.

Copilot uses AI. Check for mistakes.
Comment on lines +2 to 10
<html lang="en">
<head>
<meta charset="UTF-8" />
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/images/jan-logo.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/images/jan-logo.png"
/>
<link rel="icon" type="image/png" sizes="32x32" href="/images/jan-logo.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/images/jan-logo.png" />
<link rel="apple-touch-icon" href="/images/jan-logo.png" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Jan</title>
<!-- INJECT_GOOGLE_ANALYTICS -->
<style>
#initial-loader {
position: fixed;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 1rem;
background: hsl(var(--background, 0 0% 100%));
z-index: 9999;
opacity: 1;
transition: opacity 0.3s ease-in-out;
}

/* Light mode (default) */
@media (prefers-color-scheme: light) {
#initial-loader {
background: rgb(255, 255, 255);
}
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
#initial-loader {
background: rgb(25, 25, 25);
}
}

#initial-loader img {
width: 5rem;
height: 5rem;
animation: wave 2s ease-in-out infinite;
transform-origin: 70% 70%;
}

@keyframes wave {
0%,
100% {
transform: rotate(0deg);
}
10%,
30% {
transform: rotate(14deg);
}
20% {
transform: rotate(-8deg);
}
40%,
60% {
transform: rotate(14deg);
}
50% {
transform: rotate(-8deg);
}
70% {
transform: rotate(0deg);
}
}

.loaded #initial-loader {
opacity: 0;
pointer-events: none;
}
</style>
</head>
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The entire initial loading screen with animation and Google Analytics injection point has been removed. This affects user experience during app startup and removes analytics capability. Consider keeping a minimal loading indicator for better UX.

Copilot uses AI. Check for mistakes.
claude and others added 3 commits November 10, 2025 09:35
- Added informational message in Whisper settings
- Makes it clear that local Whisper servers don't need authentication
- Improves user experience by reducing confusion
- Create translation files for English, Spanish, French, and Russian
- Modify whisper.tsx to use useTranslation hook for all UI text
- All hardcoded strings replaced with translation keys
- Supports dynamic language switching when Jan's language changes
Remove API key validation checks to allow running local server without API key
Update validation logic in ApiKeyInput to reflect optional requirement
Add mime_guess dependency for improved MIME type handling
Copilot AI review requested due to automatic review settings November 10, 2025 10:02
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 246 out of 545 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (1)

extensions/llamacpp-extension/src/index.ts:1

  • The flash attention logic is inverted in the newer version branch. Line 1626 should check if (cfg.flash_attn) instead of if (!cfg.flash_attn) to enable flash attention when the config is true, matching the user's intent.
/**

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

if (!streamingContent || streamingContent.thread_id !== threadId) {
return null
}
if (!streamingContent || streamingContent.thread_id !== threadId) return null

Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The removed logic checked if the last message had a 'Stopped' status to prevent showing streaming content after a user stops generation. Without this check, stopped message content may incorrectly appear as streaming, causing UI confusion.

Suggested change
// Prevent showing streaming content if the last assistant message was stopped
if (lastAssistant && lastAssistant.status === 'Stopped') {
return null
}

Copilot uses AI. Check for mistakes.
Comment on lines 31 to +35
const showGenerateAIResponseBtn =
((messages[messages.length - 1]?.role === 'user' ||
(messages[messages.length - 1]?.role === 'user' ||
(messages[messages.length - 1]?.metadata &&
'tool_calls' in (messages[messages.length - 1].metadata ?? {})) ||
isPartialResponse ||
isModelMismatch) &&
!streamingContent)
'tool_calls' in (messages[messages.length - 1].metadata ?? {}))) &&
!streamingContent
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Removed logic for detecting partial responses (when user stops generation mid-stream) and model mismatches. This breaks the 'Continue' button functionality that allows users to resume interrupted responses, and prevents handling cases where the selected model differs from the one that generated a partial response.

Copilot uses AI. Check for mistakes.
threadId: string
isModelMismatch?: boolean
}) => {
export const GenerateResponseButton = ({ threadId }: { threadId: string }) => {
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Removed the isModelMismatch parameter and all related logic for continuing partial responses. This breaks the ability to continue generating from stopped messages and to handle model switches appropriately, resulting in loss of user data when switching models mid-conversation.

Copilot uses AI. Check for mistakes.
return
}
if (!prompt.trim()) {
if (!prompt.trim() && uploadedFiles.length === 0) {
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The simplified file upload system removed RAG document processing, validation, progress tracking, and ingestion status. This is a significant feature regression that removes the ability to attach and process documents for context-aware conversations.

Copilot uses AI. Check for mistakes.
#[tauri::command]
pub async fn get_mcp_configs<R: Runtime>(app: AppHandle<R>) -> Result<String, String> {
let mut path = get_jan_data_folder_path(app.clone());
pub async fn get_mcp_configs(app: AppHandle) -> Result<String, String> {
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Removed all MCP settings management including timeout configuration, restart delays, and backoff multipliers. The simplified version no longer validates or ensures settings exist in the config, potentially breaking MCP server behavior and customization.

Copilot uses AI. Check for mistakes.
};

/// Lists all threads by reading their metadata from the threads directory or database.
/// Lists all threads by reading their metadata from the threads directory.
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Removed SQLite database support for mobile platforms (iOS/Android), forcing file-based storage on all platforms. This change removes the conditional logic (should_use_sqlite()) throughout the threads module, breaking mobile platform functionality.

Copilot uses AI. Check for mistakes.
"sonner": "2.0.5",
"tailwindcss": "4.1.4",
"token.js": "npm:[email protected].30",
"token.js": "npm:[email protected].29",
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Downgraded token.js from 0.7.30 to 0.7.29. Without justification in the PR description, this appears to be an unintentional downgrade that may reintroduce bugs or remove features from the newer version.

Suggested change
"token.js": "npm:[email protected].29",
"token.js": "npm:[email protected].30",

Copilot uses AI. Check for mistakes.
authors = ["Jan <[email protected]>"]
license = "MIT"
repository = "https://github.com/janhq/jan"
repository = "https://github.com/menloresearch/jan"
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Repository URL changed from 'janhq/jan' to 'menloresearch/jan' across multiple Cargo.toml files. This appears to be an organizational change that should be explicitly mentioned in the PR description, as it affects package metadata and may break links/references.

Copilot uses AI. Check for mistakes.
"yallist": "4.0.0",
"@types/react": "19.1.2",
"@types/react-dom": "19.1.2"
"yallist": "4.0.0"
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Removed React type resolutions (@types/react and @types/react-dom). This may cause TypeScript compilation issues or type conflicts if different versions of React types are pulled in by dependencies.

Suggested change
"yallist": "4.0.0"
"yallist": "4.0.0",
"@types/react": "^18.2.62",
"@types/react-dom": "^18.2.18"

Copilot uses AI. Check for mistakes.
- Remove API Key input field from Local API Server settings UI
- Set apiKey to empty string when starting server
- Remove API key validation logic
- Local API Server now works without requiring authentication
- Remove invalid 'separator' prop from CardItem components
- Fix TypeScript compilation errors in whisper.tsx
Copilot AI review requested due to automatic review settings November 10, 2025 10:37
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 246 out of 545 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +15
{ value: 'fr', label: 'Français' },
{ value: 'ru', label: 'Русский' },
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The language entries for French ('fr') and Russian ('ru') are added but the PR title and description only mention Spanish language support. If these languages don't have complete translation files, they should be removed or the PR description should be updated to mention all three languages being added.

Suggested change
{ value: 'fr', label: 'Français' },
{ value: 'ru', label: 'Русский' },

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +31
// API key is optional for local server; no hard validation
if (!value || value.trim().length === 0) {
setError(t('common:apiKeyRequired'))
onValidationChange?.(false)
return false
setError('')
onValidationChange?.(true)
return true
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

The comment states "API key is optional for local server" but this validation function is used generically for API key inputs. This change makes all API keys optional which may not be the intended behavior for remote services. Consider adding a parameter to control whether the API key is required.

Copilot uses AI. Check for mistakes.
- Create platform feature types (FILE_ATTACHMENTS, LOCAL_API_SERVER)
- Create platform constants with feature flags
- Fix MCPToolComponentProps import by defining it locally
- Resolve TypeScript compilation errors for platform features
- Add PlatformFeature enum with FILE_ATTACHMENTS and LOCAL_API_SERVER
- Add PlatformFeatures constants mapping
- Export platform types and constants
- Add settingInterface to localStorageKey
- Add interface route to settings routes
- Fix SettingComponentProps titleKey/descriptionKey access with type cast
- Comment out @janhq/conversational-extension import (unavailable)
- Add local IngestAttachmentsResult type definition
- All 15 TypeScript errors now resolved
Copilot AI review requested due to automatic review settings November 10, 2025 10:47
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 247 out of 549 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

src-tauri/plugins/tauri-plugin-llamacpp/src/commands.rs:1

  • Removing the timeout parameter from load_llama_model and hardcoding it to 300 seconds (5 minutes) eliminates user configurability. This may cause issues for users with slower systems or larger models. Consider keeping the timeout as a configurable parameter.
use base64::{engine::general_purpose, Engine as _};

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

pub model_id: String,
pub model_path: String, // path of the loaded model
pub is_embedding: bool,
pub api_key: String,
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

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

Removing the is_embedding field from SessionInfo breaks the API contract. This is a breaking change that may affect code relying on this field to determine if a session is for embeddings.

Suggested change
pub api_key: String,
pub api_key: String,
pub is_embedding: bool,

Copilot uses AI. Check for mistakes.
@louis-jan
Copy link
Contributor

This PR introduce A LOT of irrelevant changes. Need to rework, can you rebase somehow and keep the language support change only then reopen the PR?

@louis-jan louis-jan closed this Nov 24, 2025
@github-project-automation github-project-automation bot moved this to Done in Jan Nov 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants