Skip to content

Commit 689e21c

Browse files
locnguyen1986github-roushanfredatgithubVanaliteurmauur
authored
Feat/jan server v2 migration (#6953)
* fix: standardize log timestamps to UTC timezone - Update formatTimestamp functions in both log viewers to use UTC - Replace toLocaleTimeString() with explicit UTC formatting * French Translation * feat: Allow to save the last message upon interrupting llm response * feat: Continue with AI response button if it got interrupted * feat: Continue with AI response for llamacpp * feat: Modify on-going response instead of creating new message to avoid message ID duplication * feat: Add tests for the Continuing with AI response * fix: Consolidate comments * fix: Exposing PromptProgress to be passed as param * fix: Fix tests on useChat * fix: truncated tool name available on chat input * fix: wording disable all tools * fix: Incorrect proactive icon display * feat: avoid switching model midway Once the user switches model after they interrupt the response midway, force the user to start generating the response from the beginning to avoid cross model lemma * fix: migrate flash_attn settings (#6864) * fix: migrate flash_attn settings * Update web-app/src/hooks/useModelProvider.ts Co-authored-by: Copilot <[email protected]> * Update core/src/browser/extension.ts Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]> * fix: chatinput debounce tokenize (#6855) * fix: chatinput debounce tokenize * fix error * fix: could not cancel the unintialized download (#6867) * fix: could not cancel the unintialized download * fix: could not open app folder * fix: tests * feat: loader screen before load FE * chore: remove nested RAF * chore: refactor filereader to tauri dialog * chore: update call funtion direct to handle image attachment * chore: update PR comment * Update web-app/src/locales/fr/common.json Co-authored-by: Copilot <[email protected]> * Update web-app/src/locales/fr/common.json Co-authored-by: Copilot <[email protected]> * Update web-app/src/locales/fr/common.json Co-authored-by: Copilot <[email protected]> * feat: add configurable timeout for llamacpp connections (#6872) * feat: add configurable timeout for llamacpp connections This change introduces a user-configurable read/write timeout (in seconds) for llamacpp connections, replacing the hard-coded 600s value. The timeout is now settable via the extension settings and used in both HTTP requests and server readiness checks. This provides flexibility for different deployment scenarios, allowing users to adjust connection duration based on their specific use cases while maintaining the default 10-minute timeout behavior. * fix: correct timeout conversion factor and clarify settings description The previous timeout conversion used `timeout * 100` instead of `timeout * 1000`, which incorrectly shortened the timeout to 1/10 of the intended value (e.g., 10 minutes became 1 minute). This change corrects the conversion factor to milliseconds. Additionally, the settings description was updated to explicitly state that this timeout applies to both connection and load operations, improving user understanding of its scope. * style: replace loose equality with strict equality in key comparison This change updates the comparison operator from loose equality (`==`) to strict equality (`===`) when checking for the 'timeout' key. While the key is always a string in this context (making the behavior identical), using strict equality prevents potential type conversion issues and adheres to JavaScript best practices for reliable comparisons. * fix: hide thread dropdown on delete dialog confirmation popup * fix: model download state update (#6882) * Fix Discord Community link in CONTRIBUTING.md (#6883) * feat: Russian localization (#6869) * Add files via upload Updating localization files * Update LanguageSwitcher.tsx Added Russian language option * Add files via upload Removing the trailing newline character * Add files via upload UI Testing, Translation & Contextual QA * chore: address PR comments * feat: replace Tauri dialog plugin with rfd integration (#6850) * feat: replace Tauri dialog plugin with rfd integration Remove the legacy `tauri-plugin-dialog` dependency and its capability entry, adding `rfd` as a cross‑platform native file dialog library. Introduce `open_dialog` and `save_dialog` commands that expose file‑selection and save dialogs to the frontend, along with a `DialogOpenOptions` model for filter, directory, and multiple‑file support. Update the `TauriDialogService` to invoke these new commands instead of the removed plugin, ensuring a cleaner build and consistent dialog behaviour across desktop targets. * chore: remove unused serde_json import Remove the unnecessary serde_json import from `src-tauri/src/core/filesystem/commands.rs` to keep the codebase clean and eliminate unused dependencies. This small refactor improves build clarity and reduces potential lint warnings. * fix: command + N does not work (#6890) * fix: add mcp tool call timeout config (#6891) Update web-app/src/locales/vn/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update web-app/src/locales/zh-CN/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update web-app/src/locales/pl/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update web-app/src/locales/pt-BR/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update web-app/src/locales/de-DE/mcp-servers.json Co-authored-by: Copilot <[email protected]> fix: tests Update web-app/src/locales/ja/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update web-app/src/locales/zh-TW/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update web-app/src/locales/id/mcp-servers.json Co-authored-by: Copilot <[email protected]> Update src-tauri/src/core/mcp/commands.rs Co-authored-by: Copilot <[email protected]> fix: utf translation * Fix: add conditional RAG tool injection only on document attachment (#6887) * feat: add conditional RAG tool injection for attachments The chat logic now only requests RAG tools when document attachments are enabled and the model supports tools. This improves performance by avoiding unnecessary API calls and reduces payloads for models that do not need external knowledge. The change also cleans up temporary chat messages on reload, sets a navigation flag, and updates `sendCompletion` and `postMessageProcessing` to use the new conditional tool loading logic. The refactor introduces clearer imports and formatting. * chore: restore formatting * completion.ts: restore formatting * feat: track document attachment in thread metadata and update RAG logic Add a `hasDocuments` flag to the active thread’s metadata when a document is ingested. Update the RAG eligibility check to use this flag rather than the raw `documents` array, ensuring that the thread’s state accurately reflects its attachment status. This keeps the thread UI in sync with attachments and prevents unnecessary re‑processing when the same documents are added to a thread. * refactor: consolidate thread update after attachment ingestion Remove duplicate `useThreads.getState().updateThread` calls that were present inside the attachment ingestion logic. The previous implementation updated the thread metadata twice (once inside the `try` block and again later), which could lead to unnecessary state changes and made debugging harder. The new approach updates the thread only once, after all attachments have been processed, ensuring consistent metadata and simplifying the flow. * test: improve useChat test mocks and capability handling Refactor the test environment for `useChat`: - Updated the `useModelProvider` mock to expose a test model with full capabilities (`tools`, `vision`, `proactive`) and a matching provider, enabling the hook to perform model‑specific logic without runtime errors. - Added a `setTokenSpeed` mock to `useAppState` to satisfy the hook’s usage of token‑speed settings. - Refactored `useThreads` to use `Object.assign` for consistent selector behaviour and added a `getThreadById` implementation. - Introduced an attachments mock and platform feature constants so that attachment handling tests can execute correctly. - Normalised content arrays in `newUserThreadContent` and `newAssistantThreadContent` to match the actual content format. - Cleared and reset builder mocks in `beforeEach` to avoid stale state across test cases. - Made minor formatting and type corrections throughout the test file. These changes resolve failing tests caused by missing provider models, incomplete capabilities, and broken mocks, and they enable coverage of proactive mode detection and attachment handling. * fix: glibc linux * feat: hide file attachments properly (#6895) * Guard attachment setters when feature disabled * fix lint issue * fix: get mcp servers spam request issue (#6901) * resolve rust clippy warnings (#6888) * resolve rust clippy warnings * fix: start_server expects a single config * resolve eslint error * fix(#6902): update Bun download link for darwin-86x -> darwin-64x (#6903) * fix: regression on reasoning models (#6914) * fix: regression on reasoning models * fix: reset accumulated text when not continuing message generation * fix: new chat shortcut stopped working (#6915) * fix: glitch UI issues (#6916) * fix: glitch UI issues * fix: tests * chore: bump rmcp to 0.8.5 (#6918) * feat: add backend migration mapping and update backend handling (#6917) Added `mapOldBackendToNew` to translate legacy backend strings (e.g., `win-avx2-x64`, `win-avx512-cuda-cu12.0-x64`) into the new unified names (`win-common_cpus-x64`, `win-cuda-12-common_cpus-x64`). Updated backend selection, installation, and download logic to use the mapper, ensuring consistent naming across the extension and tests. Updated tests to verify the mapping, new download items, and correct extraction paths. Minor formatting updates to the Tauri command file for clearer logging. This change enables smoother migration for stored user preferences and reduces duplicate asset handling. * add temp auth fix * add image upload * presigned upload * fix image upload and refresh tokens * fix images extensions * add project extensions * dev for testing --------- Co-authored-by: Roushan Singh <[email protected]> Co-authored-by: Roushan Kumar Singh <[email protected]> Co-authored-by: fred <[email protected]> Co-authored-by: Vanalite <[email protected]> Co-authored-by: Faisal Amir <[email protected]> Co-authored-by: Louis <[email protected]> Co-authored-by: Copilot <[email protected]> Co-authored-by: Dinh Long Nguyen <[email protected]> Co-authored-by: Akarshan Biswas <[email protected]> Co-authored-by: @Kuzmich55 <[email protected]> Co-authored-by: Minh141120 <[email protected]> Co-authored-by: Nguyen Ngoc Minh <[email protected]> Co-authored-by: Volodya Lombrozo <[email protected]>
1 parent 3ba7d6e commit 689e21c

File tree

183 files changed

+10037
-1564
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

183 files changed

+10037
-1564
lines changed

.github/workflows/jan-tauri-build-nightly.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ jobs:
116116
build-linux-x64,
117117
build-macos,
118118
]
119-
runs-on: ubuntu-latest
119+
runs-on: ubuntu-22.04
120120
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
121121
steps:
122122
- name: Getting the repo

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ Common issues:
237237
## Getting Help
238238

239239
- [Documentation](https://jan.ai/docs) - The manual you should read
240-
- [Discord Community](https://discord.gg/jan) - Where the community lives
240+
- [Discord Community](https://discord.gg/FTk2MvZwJH) - Where the community lives
241241
- [GitHub Issues](https://github.com/janhq/jan/issues) - Report bugs here
242242
- [GitHub Discussions](https://github.com/janhq/jan/discussions) - Ask questions
243243

core/src/browser/extension.test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,54 @@ describe('BaseExtension', () => {
149149
JSON.stringify([{ key: 'setting1', controllerProps: { value: 'newValue' } }])
150150
)
151151
})
152+
153+
it('should reset dropdown value when persisted value is no longer valid', async () => {
154+
localStorage.clear()
155+
156+
const oldSettings = [
157+
{
158+
key: 'flash_attn',
159+
controllerProps: {
160+
value: 'ON',
161+
options: [
162+
{ value: 'auto', name: 'Auto' },
163+
{ value: 'on', name: 'ON' },
164+
{ value: 'off', name: 'OFF' },
165+
],
166+
},
167+
},
168+
]
169+
170+
localStorage.setItem('TestExtension', JSON.stringify(oldSettings))
171+
172+
const newSettings: SettingComponentProps[] = [
173+
{
174+
key: 'flash_attn',
175+
controllerProps: {
176+
value: 'auto',
177+
options: [
178+
{ value: 'auto', name: 'Auto' },
179+
{ value: 'on', name: 'On' },
180+
{ value: 'off', name: 'Off' },
181+
],
182+
},
183+
} as any,
184+
]
185+
186+
const setItemSpy = vi.spyOn(localStorage, 'setItem')
187+
188+
await baseExtension.registerSettings(newSettings)
189+
190+
expect(setItemSpy).toHaveBeenCalled()
191+
const [, latestPayload] = setItemSpy.mock.calls[setItemSpy.mock.calls.length - 1]
192+
const persistedSettings = JSON.parse(latestPayload)
193+
const flashSetting = persistedSettings.find(
194+
(setting: any) => setting.key === 'flash_attn'
195+
)
196+
197+
expect(flashSetting.controllerProps.value).toBe('auto')
198+
199+
setItemSpy.mockRestore()
200+
localStorage.clear()
201+
})
152202
})

core/src/browser/extension.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export enum ExtensionTypeEnum {
1313
Hardware = 'hardware',
1414
RAG = 'rag',
1515
VectorDB = 'vectorDB',
16+
Project = 'project',
1617
}
1718

1819
export interface ExtensionType {
@@ -131,10 +132,14 @@ export abstract class BaseExtension implements ExtensionType {
131132
setting.controllerProps.value =
132133
oldSettings.find((e: any) => e.key === setting.key)?.controllerProps?.value ??
133134
setting.controllerProps.value
134-
if ('options' in setting.controllerProps)
135+
if ('options' in setting.controllerProps) {
135136
setting.controllerProps.options = setting.controllerProps.options?.length
136137
? setting.controllerProps.options
137138
: oldSettings.find((e: any) => e.key === setting.key)?.controllerProps?.options
139+
if(!setting.controllerProps.options?.some(e => e.value === setting.controllerProps.value)) {
140+
setting.controllerProps.value = setting.controllerProps.options?.[0]?.value ?? setting.controllerProps.value
141+
}
142+
}
138143
if ('recommended' in setting.controllerProps) {
139144
const oldRecommended = oldSettings.find((e: any) => e.key === setting.key)
140145
?.controllerProps?.recommended

core/src/browser/extensions/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ export { AssistantExtension } from './assistant'
1919
*/
2020
export { MCPExtension } from './mcp'
2121

22+
/**
23+
* Project extension for managing projects/folders.
24+
*/
25+
export { ProjectExtension } from './project'
26+
2227
/**
2328
* Base AI Engines.
2429
*/
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {
2+
Project,
3+
ProjectInterface,
4+
CreateProjectRequest,
5+
UpdateProjectRequest,
6+
ListProjectsParams,
7+
ListProjectsResponse,
8+
DeleteProjectResponse,
9+
} from '../../types'
10+
import { BaseExtension, ExtensionTypeEnum } from '../extension'
11+
12+
/**
13+
* Project extension. Manages projects/folders for organizing threads.
14+
* @abstract
15+
* @extends BaseExtension
16+
*/
17+
export abstract class ProjectExtension
18+
extends BaseExtension
19+
implements ProjectInterface
20+
{
21+
/**
22+
* Project extension type.
23+
*/
24+
type(): ExtensionTypeEnum | undefined {
25+
return ExtensionTypeEnum.Project
26+
}
27+
28+
abstract getAllProjects(): Promise<Project[]>
29+
abstract createProject(data: CreateProjectRequest): Promise<Project>
30+
abstract getProject(projectId: string): Promise<Project | null>
31+
abstract updateProject(projectId: string, data: UpdateProjectRequest): Promise<Project>
32+
abstract deleteProject(projectId: string): Promise<void>
33+
abstract listProjects(params?: ListProjectsParams): Promise<ListProjectsResponse>
34+
abstract favoriteProject(projectId: string, isFavorite: boolean): Promise<Project>
35+
abstract archiveProject(projectId: string, isArchived: boolean): Promise<Project>
36+
}

core/src/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ export * from './setting'
1111
export * from './engine'
1212
export * from './hardware'
1313
export * from './mcp'
14+
export * from './project'

core/src/types/message/messageInterface.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ export interface MessageInterface {
2020
*/
2121
listMessages(threadId: string): Promise<ThreadMessage[]>
2222

23+
/**
24+
* Updates an existing message in a thread.
25+
* @param {ThreadMessage} message - The message to be updated (must have existing ID).
26+
* @returns {Promise<ThreadMessage>} A promise that resolves to the updated message.
27+
*/
28+
modifyMessage(message: ThreadMessage): Promise<ThreadMessage>
29+
2330
/**
2431
* Deletes a specific message from a thread.
2532
* @param {string} threadId - The ID of the thread from which the message will be deleted.

core/src/types/project/index.ts

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/**
2+
* Project Management Types
3+
* Types for project/folder management operations
4+
*/
5+
6+
/**
7+
* Project object
8+
*/
9+
export interface Project {
10+
/** Unique identifier */
11+
id: string
12+
/** Object type */
13+
object: 'project'
14+
/** Project name */
15+
name: string
16+
/** Optional instruction/description for the project */
17+
instruction?: string
18+
/** Whether the project is marked as favorite */
19+
is_favorite: boolean
20+
/** Whether the project is archived */
21+
is_archived: boolean
22+
/** Timestamp when project was archived (if applicable) */
23+
archived_at?: number
24+
/** Creation timestamp (number) */
25+
created_at: number
26+
/** Last update timestamp (number) */
27+
updated_at: number
28+
}
29+
30+
/**
31+
* Request payload for creating a new project
32+
*/
33+
export interface CreateProjectRequest {
34+
/** Project name */
35+
name: string
36+
/** Optional instruction/description for the project */
37+
instruction?: string
38+
}
39+
40+
/**
41+
* Request payload for updating an existing project
42+
*/
43+
export interface UpdateProjectRequest {
44+
/** Updated project name */
45+
name?: string
46+
/** Updated instruction/description */
47+
instruction?: string
48+
/** Update favorite status */
49+
is_favorite?: boolean
50+
/** Update archived status */
51+
is_archived?: boolean
52+
}
53+
54+
/**
55+
* Parameters for listing projects
56+
*/
57+
export interface ListProjectsParams {
58+
/** Maximum number of projects to return */
59+
limit?: number
60+
/** Cursor for pagination */
61+
cursor?: string
62+
}
63+
64+
/**
65+
* Response for listing projects
66+
*/
67+
export interface ListProjectsResponse {
68+
/** Object type */
69+
object: 'list'
70+
/** Array of projects */
71+
data: Project[]
72+
/** ID of first item */
73+
first_id?: string
74+
/** ID of last item */
75+
last_id?: string
76+
/** Cursor for next page */
77+
next_cursor?: string
78+
/** Whether there are more items */
79+
has_more: boolean
80+
/** Total number of projects */
81+
total: number
82+
}
83+
84+
/**
85+
* Response for deleting a project
86+
*/
87+
export interface DeleteProjectResponse {
88+
/** Project ID that was deleted */
89+
id: string
90+
/** Object type */
91+
object: 'project'
92+
/** Whether deletion was successful */
93+
deleted: boolean
94+
}
95+
96+
/**
97+
* Project Extension Interface
98+
* Defines methods for project management operations
99+
*/
100+
export interface ProjectInterface {
101+
/**
102+
* Get all projects
103+
*/
104+
getAllProjects(): Promise<Project[]>
105+
106+
/**
107+
* Create a new project
108+
* @param data Project creation request
109+
*/
110+
createProject(data: CreateProjectRequest): Promise<Project>
111+
112+
/**
113+
* Get a project by ID
114+
* @param projectId Project identifier
115+
*/
116+
getProject(projectId: string): Promise<Project | null>
117+
118+
/**
119+
* Update a project
120+
* @param projectId Project identifier
121+
* @param data Project update request
122+
*/
123+
updateProject(projectId: string, data: UpdateProjectRequest): Promise<Project>
124+
125+
/**
126+
* Delete a project
127+
* @param projectId Project identifier
128+
*/
129+
deleteProject(projectId: string): Promise<void>
130+
131+
/**
132+
* List projects with pagination
133+
* @param params List parameters
134+
*/
135+
listProjects(params?: ListProjectsParams): Promise<ListProjectsResponse>
136+
137+
/**
138+
* Mark a project as favorite
139+
* @param projectId Project identifier
140+
* @param isFavorite Whether to favorite or unfavorite
141+
*/
142+
favoriteProject(projectId: string, isFavorite: boolean): Promise<Project>
143+
144+
/**
145+
* Archive or unarchive a project
146+
* @param projectId Project identifier
147+
* @param isArchived Whether to archive or unarchive
148+
*/
149+
archiveProject(projectId: string, isArchived: boolean): Promise<Project>
150+
}

0 commit comments

Comments
 (0)