Browse Source

Merge branch 'main' into bugfix/dark-mode-border-color-of-drop-area-in-import-activities-dialog

pull/8134/head
Thomas Kaul 4 days ago
committed by GitHub
parent
commit
f84494a63a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 6
      apps/api/src/app/endpoints/ai/ai.service.spec.ts
  3. 22
      apps/api/src/app/endpoints/ai/ai.service.ts
  4. 4
      package-lock.json
  5. 2
      package.json

2
CHANGELOG.md

@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fixed the border color of the drop area in the import activities dialog (dark mode) - Fixed the border color of the drop area in the import activities dialog (dark mode)
## 3.84.0 - 2026-10-11 ## 3.84.2 - 2026-10-11
### Added ### Added

6
apps/api/src/app/endpoints/ai/ai.service.spec.ts

@ -197,7 +197,7 @@ describe('AiService', () => {
); );
}); });
it('Restricts the routing to endpoints with zero data retention and passes a PDF file to the model itself', async () => { it('Restricts the routing to endpoints with zero data retention, disables the reasoning and passes a PDF file to the model itself', async () => {
await aiService.getActivityRowsFromFile({ await aiService.getActivityRowsFromFile({
file: { buffer: Buffer.from('%PDF-1.7'), mediaType: 'application/pdf' }, file: { buffer: Buffer.from('%PDF-1.7'), mediaType: 'application/pdf' },
locale: 'de-CH' locale: 'de-CH'
@ -206,6 +206,7 @@ describe('AiService', () => {
expect(chat).toHaveBeenCalledWith('vision-model', { expect(chat).toHaveBeenCalledWith('vision-model', {
plugins: [{ id: 'file-parser', pdf: { engine: 'native' } }], plugins: [{ id: 'file-parser', pdf: { engine: 'native' } }],
provider: { require_parameters: true, zdr: true }, provider: { require_parameters: true, zdr: true },
reasoning: { effort: 'none' },
usage: { include: true } usage: { include: true }
}); });
}); });
@ -892,7 +893,7 @@ describe('AiService', () => {
}); });
}); });
it('Restricts the routing to endpoints with zero data retention, limits the number of steps, requires a tool call in the first step and allows no tool call in the last step', async () => { it('Restricts the routing to endpoints with zero data retention, disables the reasoning, limits the number of steps, requires a tool call in the first step and allows no tool call in the last step', async () => {
mockRowMatches({}); mockRowMatches({});
await aiService.getActivitiesFromRows({ await aiService.getActivitiesFromRows({
@ -905,6 +906,7 @@ describe('AiService', () => {
expect(chat).toHaveBeenCalledWith('agent-model', { expect(chat).toHaveBeenCalledWith('agent-model', {
provider: { require_parameters: true, zdr: true }, provider: { require_parameters: true, zdr: true },
reasoning: { effort: 'none' },
usage: { include: true } usage: { include: true }
}); });

22
apps/api/src/app/endpoints/ai/ai.service.ts

@ -289,11 +289,12 @@ export class AiService {
* OpenRouter is not covered by the zero data retention. The model gets no * OpenRouter is not covered by the zero data retention. The model gets no
* tools and copies the asset, the account and the broker as printed, hence * tools and copies the asset, the account and the broker as printed, hence
* the rows still have to be matched to asset profiles and accounts. The * the rows still have to be matched to asset profiles and accounts. The
* name of the file is passed as well, as it can name the broker. A row above the * name of the file is passed as well, as it can name the broker. The
* maximum number of activities is left out. An output which reaches the * reasoning is disabled, as it can add thousands of output tokens even for a
* maximum number of output tokens is cut, hence it gives an error for the * single row. A row above the maximum number of activities is left out. An
* caller. A cut output without any text is not parsed at all, hence the * output which reaches the maximum number of output tokens is cut, hence it
* finish reason is checked as well. * gives an error for the caller. A cut output without any text is not parsed
* at all, hence the finish reason is checked as well.
*/ */
public async getActivityRowsFromFile({ public async getActivityRowsFromFile({
abortSignal, abortSignal,
@ -341,6 +342,7 @@ export class AiService {
settings: { settings: {
plugins: [{ id: 'file-parser', pdf: { engine: 'native' } }], plugins: [{ id: 'file-parser', pdf: { engine: 'native' } }],
provider: { require_parameters: true, zdr: true }, provider: { require_parameters: true, zdr: true },
reasoning: { effort: 'none' },
usage: { include: true } usage: { include: true }
} }
}), }),
@ -517,10 +519,11 @@ export class AiService {
* tools search-asset-profiles and get-accounts of the server of the Model * tools search-asset-profiles and get-accounts of the server of the Model
* Context Protocol. The accounts are given without values. The first step * Context Protocol. The accounts are given without values. The first step
* requires a tool call, as a model can give the matches without any tool * requires a tool call, as a model can give the matches without any tool
* call otherwise. The last step allows no tool call, so that the model * call otherwise. The reasoning is disabled, as some models ignore a
* always gives the matches. An asset match whose asset profile no search * required tool call while they reason. The last step allows no tool call,
* gave is left out, as the import refuses a symbol which the data source * so that the model always gives the matches. An asset match whose asset
* cannot resolve. * profile no search gave is left out, as the import refuses a symbol which
* the data source cannot resolve.
*/ */
private async getRowMatches({ private async getRowMatches({
abortSignal, abortSignal,
@ -555,6 +558,7 @@ export class AiService {
modelPropertyKey: PROPERTY_OPENROUTER_MODEL_AGENT, modelPropertyKey: PROPERTY_OPENROUTER_MODEL_AGENT,
settings: { settings: {
provider: { require_parameters: true, zdr: true }, provider: { require_parameters: true, zdr: true },
reasoning: { effort: 'none' },
usage: { include: true } usage: { include: true }
} }
}), }),

4
package-lock.json

@ -1,12 +1,12 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "3.84.0", "version": "3.84.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ghostfolio", "name": "ghostfolio",
"version": "3.84.0", "version": "3.84.2",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

2
package.json

@ -1,6 +1,6 @@
{ {
"name": "ghostfolio", "name": "ghostfolio",
"version": "3.84.0", "version": "3.84.2",
"homepage": "https://ghostfol.io", "homepage": "https://ghostfol.io",
"license": "AGPL-3.0", "license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio", "repository": "https://github.com/ghostfolio/ghostfolio",

Loading…
Cancel
Save