diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a0457982c..e91bca4421 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgraded `ai` from version `7.0.114` to `7.0.127` -## 3.84.0 - 2026-10-11 +## 3.84.2 - 2026-10-11 ### Added diff --git a/apps/api/src/app/endpoints/ai/ai.service.spec.ts b/apps/api/src/app/endpoints/ai/ai.service.spec.ts index b2bb63addc..549bdcef35 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.spec.ts +++ b/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({ file: { buffer: Buffer.from('%PDF-1.7'), mediaType: 'application/pdf' }, locale: 'de-CH' @@ -206,6 +206,7 @@ describe('AiService', () => { expect(chat).toHaveBeenCalledWith('vision-model', { plugins: [{ id: 'file-parser', pdf: { engine: 'native' } }], provider: { require_parameters: true, zdr: true }, + reasoning: { effort: 'none' }, 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({}); await aiService.getActivitiesFromRows({ @@ -905,6 +906,7 @@ describe('AiService', () => { expect(chat).toHaveBeenCalledWith('agent-model', { provider: { require_parameters: true, zdr: true }, + reasoning: { effort: 'none' }, usage: { include: true } }); diff --git a/apps/api/src/app/endpoints/ai/ai.service.ts b/apps/api/src/app/endpoints/ai/ai.service.ts index 3c30ea8e15..006b47a358 100644 --- a/apps/api/src/app/endpoints/ai/ai.service.ts +++ b/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 * 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 - * name of the file is passed as well, as it can name the broker. A row above the - * maximum number of activities is left out. An output which reaches the - * maximum number of output tokens is cut, hence it 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. + * name of the file is passed as well, as it can name the broker. The + * reasoning is disabled, as it can add thousands of output tokens even for a + * single row. A row above the maximum number of activities is left out. An + * output which reaches the maximum number of output tokens is cut, hence it + * 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({ abortSignal, @@ -341,6 +342,7 @@ export class AiService { settings: { plugins: [{ id: 'file-parser', pdf: { engine: 'native' } }], provider: { require_parameters: true, zdr: true }, + reasoning: { effort: 'none' }, usage: { include: true } } }), @@ -517,10 +519,11 @@ export class AiService { * tools search-asset-profiles and get-accounts of the server of the Model * 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 - * call otherwise. The last step allows no tool call, so that the model - * always gives the matches. An asset match whose asset profile no search - * gave is left out, as the import refuses a symbol which the data source - * cannot resolve. + * call otherwise. The reasoning is disabled, as some models ignore a + * required tool call while they reason. The last step allows no tool call, + * so that the model always gives the matches. An asset match whose asset + * profile no search gave is left out, as the import refuses a symbol which + * the data source cannot resolve. */ private async getRowMatches({ abortSignal, @@ -555,6 +558,7 @@ export class AiService { modelPropertyKey: PROPERTY_OPENROUTER_MODEL_AGENT, settings: { provider: { require_parameters: true, zdr: true }, + reasoning: { effort: 'none' }, usage: { include: true } } }), diff --git a/package-lock.json b/package-lock.json index 6e1efdd6a7..7522246234 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "ghostfolio", - "version": "3.84.0", + "version": "3.84.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ghostfolio", - "version": "3.84.0", + "version": "3.84.2", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index ec3e7eca2d..b1879a80f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ghostfolio", - "version": "3.84.0", + "version": "3.84.2", "homepage": "https://ghostfol.io", "license": "AGPL-3.0", "repository": "https://github.com/ghostfolio/ghostfolio",