diff --git a/api/package.json b/api/package.json index cc50bcb81c..3a8da6e644 100644 --- a/api/package.json +++ b/api/package.json @@ -46,7 +46,7 @@ "@azure/storage-blob": "^12.30.0", "@google/genai": "^2.8.0", "@keyv/redis": "^4.3.3", - "@librechat/agents": "^3.2.38", + "@librechat/agents": "^3.2.41", "@librechat/api": "*", "@librechat/data-schemas": "*", "@microsoft/microsoft-graph-client": "^3.0.7", diff --git a/e2e/setup/fake-model.js b/e2e/setup/fake-model.js index 77f1d98a34..c2ce714b56 100644 --- a/e2e/setup/fake-model.js +++ b/e2e/setup/fake-model.js @@ -427,7 +427,7 @@ Created by the Playwright mock e2e suite to verify host file authoring without c function buildCreateSkillArgs(skillName) { return { - file_path: `skills/${skillName}/SKILL.md`, + path: `skills/${skillName}/SKILL.md`, content: buildSkillBody(skillName), overwrite: false, }; @@ -435,7 +435,7 @@ function buildCreateSkillArgs(skillName) { function buildEditSkillArgs(skillName) { return { - file_path: `skills/${skillName}/SKILL.md`, + path: `skills/${skillName}/SKILL.md`, old_text: `description: ${SKILL_DESCRIPTION}`, new_text: `description: ${EDITED_SKILL_DESCRIPTION}`, }; diff --git a/package-lock.json b/package-lock.json index 966e1c6a0e..097132596b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "@azure/storage-blob": "^12.30.0", "@google/genai": "^2.8.0", "@keyv/redis": "^4.3.3", - "@librechat/agents": "^3.2.38", + "@librechat/agents": "^3.2.41", "@librechat/api": "*", "@librechat/data-schemas": "*", "@microsoft/microsoft-graph-client": "^3.0.7", @@ -9834,9 +9834,9 @@ } }, "node_modules/@librechat/agents": { - "version": "3.2.38", - "resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.2.38.tgz", - "integrity": "sha512-jbD+H9T/Bcz2ot50X2J/Ffsq5McFHriS66AhFHMIzUfsbDVbLFSYLj/6K61JRjxegIZ/z/gV6tmVAmZCHWh5kg==", + "version": "3.2.41", + "resolved": "https://registry.npmjs.org/@librechat/agents/-/agents-3.2.41.tgz", + "integrity": "sha512-AjzSrurK/ihORn4NIftlS5CCviBWcT2kkLvYoCuV/aRT2E4HQea6aUfC+g0FIK71pBN9RThQv7Gh3I/7/aMxIw==", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "^0.92.0", @@ -11538,7 +11538,8 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", @@ -11557,12 +11558,12 @@ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" }, "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "license": "BSD-3-Clause", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "@protobufjs/aspromise": "^1.1.1" } }, "node_modules/@protobufjs/float": { @@ -11571,9 +11572,9 @@ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" }, "node_modules/@protobufjs/inquire": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", - "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.2.tgz", + "integrity": "sha512-pa0vFRuws4wkvaXKK1uXZMAwAX4/t8ANaJo45iw/oQHNQ9q5xUzwgFmVJGXiga2BeN+zpX7Vf9vmsiIa2J+MUw==", "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { @@ -35755,9 +35756,9 @@ } }, "node_modules/protobufjs": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.8.tgz", - "integrity": "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.9.tgz", + "integrity": "sha512-Od4muIm3HW1AouyHF5lONOf1FWo3hY1NbFDoy191X9GzhpgW1clCoaFjfVs2rKJNFYpTNJbje4cbAIDBZJ63ZA==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -35765,9 +35766,9 @@ "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", + "@protobufjs/fetch": "^1.1.1", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.1", + "@protobufjs/inquire": "^1.1.2", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.1", @@ -40365,9 +40366,9 @@ "license": "MIT" }, "node_modules/undici": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.1.tgz", - "integrity": "sha512-5xoBibbmnjlcR3jdqtY2Lnx7WbrD/tHlT01TmvqZUFVc9Q1w4+j5hbnapTqbcXITMH1ovjq/W7BkqBilHiVAaA==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", "license": "MIT", "engines": { "node": ">=20.18.1" @@ -42389,7 +42390,7 @@ "@azure/storage-blob": "^12.30.0", "@google/genai": "^2.8.0", "@keyv/redis": "^4.3.3", - "@librechat/agents": "^3.2.38", + "@librechat/agents": "^3.2.41", "@librechat/data-schemas": "*", "@modelcontextprotocol/sdk": "^1.29.0", "@opentelemetry/api": "^1.9.0", diff --git a/packages/api/package.json b/packages/api/package.json index 28b18ae90e..913408d94b 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -113,7 +113,7 @@ "@azure/storage-blob": "^12.30.0", "@google/genai": "^2.8.0", "@keyv/redis": "^4.3.3", - "@librechat/agents": "^3.2.38", + "@librechat/agents": "^3.2.41", "@librechat/data-schemas": "*", "@modelcontextprotocol/sdk": "^1.29.0", "@opentelemetry/api": "^1.9.0", diff --git a/packages/api/src/agents/__tests__/initialize.test.ts b/packages/api/src/agents/__tests__/initialize.test.ts index e770dbd630..601d4706fd 100644 --- a/packages/api/src/agents/__tests__/initialize.test.ts +++ b/packages/api/src/agents/__tests__/initialize.test.ts @@ -11,7 +11,7 @@ jest.mock('@librechat/agents', () => ({ parameters: { type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'For skill files: "{skillName}/{path}".', }, diff --git a/packages/api/src/agents/handlers.spec.ts b/packages/api/src/agents/handlers.spec.ts index 0d843c9290..f195837735 100644 --- a/packages/api/src/agents/handlers.spec.ts +++ b/packages/api/src/agents/handlers.spec.ts @@ -673,7 +673,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_5', name: Constants.READ_FILE, - args: { file_path: 'maybe-disabled-read/SKILL.md' }, + args: { path: 'maybe-disabled-read/SKILL.md' }, }, ]); @@ -717,7 +717,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_6', name: Constants.READ_FILE, - args: { file_path: 'manually-primed/references/foo.md' }, + args: { path: 'manually-primed/references/foo.md' }, }, ]); @@ -766,7 +766,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_1', name: Constants.READ_FILE, - args: { file_path: 'pii-redactor/SKILL.md' }, + args: { path: 'pii-redactor/SKILL.md' }, }, ]); @@ -795,7 +795,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_2', name: Constants.READ_FILE, - args: { file_path: 'normal-skill/SKILL.md' }, + args: { path: 'normal-skill/SKILL.md' }, }, ]); @@ -833,7 +833,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_3', name: Constants.READ_FILE, - args: { file_path: 'manual-only-skill/SKILL.md' }, + args: { path: 'manual-only-skill/SKILL.md' }, }, ]); @@ -869,7 +869,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_4', name: Constants.READ_FILE, - args: { file_path: 'other-disabled-skill/SKILL.md' }, + args: { path: 'other-disabled-skill/SKILL.md' }, }, ]); @@ -911,7 +911,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_always', name: Constants.READ_FILE, - args: { file_path: 'always-applied-legal/SKILL.md' }, + args: { path: 'always-applied-legal/SKILL.md' }, }, ]); @@ -947,7 +947,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_pin', name: Constants.READ_FILE, - args: { file_path: 'collides/SKILL.md' }, + args: { path: 'collides/SKILL.md' }, }, ]); @@ -1093,7 +1093,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_skill', name: 'create_file', args: { - file_path: 'skills/new-skill/SKILL.md', + path: 'skills/new-skill/SKILL.md', content: '---\nname: new-skill\ndescription: Use for tests\ndisable-model-invocation: true\nallowed-tools:\n - execute_code\n---\n# New skill\n', }, @@ -1140,7 +1140,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_auto_frontmatter', name: 'create_file', args: { - file_path: 'skills/auto-skill/SKILL.md', + path: 'skills/auto-skill/SKILL.md', content: '# Auto skill\nUse this skill when testing generated frontmatter.\n', }, }, @@ -1179,7 +1179,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_block_description', name: 'create_file', args: { - file_path: 'skills/block-description-skill/SKILL.md', + path: 'skills/block-description-skill/SKILL.md', content: '---\nname: block-description-skill\ndescription: |-\n Use this skill for long descriptions.\n Keep both lines searchable.\n---\n# Block description skill\n', }, @@ -1233,7 +1233,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_skill', name: 'create_file', args: { - file_path: 'skills/new-skill/SKILL.md', + path: 'skills/new-skill/SKILL.md', content: '---\nname: new-skill\ndescription: Use for tests\n---\n# New skill\n', }, }, @@ -1241,7 +1241,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_reference', name: 'create_file', args: { - file_path: 'skills/new-skill/references/a.md', + path: 'skills/new-skill/references/a.md', content: 'reference text', }, }, @@ -1307,7 +1307,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_round_skill', name: 'create_file', args: { - file_path: 'skills/round-skill/SKILL.md', + path: 'skills/round-skill/SKILL.md', content: createdSkill.body, }, }, @@ -1320,7 +1320,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_read_round_skill', name: Constants.READ_FILE, - args: { file_path: 'skills/round-skill/SKILL.md' }, + args: { path: 'skills/round-skill/SKILL.md' }, }, ], runtimeConfigurable, @@ -1357,7 +1357,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_existing', name: 'create_file', args: { - file_path: 'skills/existing-skill/SKILL.md', + path: 'skills/existing-skill/SKILL.md', content: '---\nname: existing-skill\ndescription: Use for tests\n---\n# Updated\n', }, }, @@ -1396,7 +1396,7 @@ describe('createToolExecuteHandler', () => { id: 'call_duplicate_stale_skill', name: 'create_file', args: { - file_path: 'skills/stale-skill/SKILL.md', + path: 'skills/stale-skill/SKILL.md', content: '---\nname: stale-skill\ndescription: Replacement\n---\n# Replacement\n', }, }, @@ -1437,7 +1437,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_excluded_skill', name: 'edit_file', args: { - file_path: 'skills/excluded-skill/SKILL.md', + path: 'skills/excluded-skill/SKILL.md', old_text: '# Excluded', new_text: '# Changed', }, @@ -1477,7 +1477,7 @@ describe('createToolExecuteHandler', () => { id: 'call_recovered_hidden_skill', name: 'edit_file', args: { - file_path: 'skills/hidden-recovered-skill/SKILL.md', + path: 'skills/hidden-recovered-skill/SKILL.md', old_text: '# Hidden', new_text: '# Changed', }, @@ -1519,7 +1519,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_file', name: 'edit_file', args: { - file_path: 'skills/edit-skill/references/a.md', + path: 'skills/edit-skill/references/a.md', old_text: 'hello old', new_text: 'hello new', }, @@ -1581,7 +1581,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_stale_bundled_file', name: 'edit_file', args: { - file_path: 'skills/edit-skill/references/a.md', + path: 'skills/edit-skill/references/a.md', old_text: 'hello old', new_text: 'hello new', }, @@ -1624,7 +1624,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_skill_md_frontmatter', name: 'edit_file', args: { - file_path: 'skills/runtime-skill/SKILL.md', + path: 'skills/runtime-skill/SKILL.md', old_text: 'description: Use before\naction: ignored', new_text: 'description: Use before\nuser-invocable: false\ndisable-model-invocation: true\nallowed-tools:\n - execute_code\nalways-apply: true', @@ -1677,7 +1677,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_skill_md_block_description', name: 'edit_file', args: { - file_path: 'skills/runtime-skill/SKILL.md', + path: 'skills/runtime-skill/SKILL.md', old_text: 'description: Use before', new_text: 'description: |-\n Use this skill for long descriptions.\n Keep both lines searchable.', @@ -1717,7 +1717,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_skill_md_name', name: 'edit_file', args: { - file_path: 'skills/runtime-skill/SKILL.md', + path: 'skills/runtime-skill/SKILL.md', old_text: 'name: runtime-skill', new_text: 'name: dev-toolkit', }, @@ -1759,7 +1759,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_ambiguous', name: 'edit_file', args: { - file_path: 'skills/ambiguous-skill/references/a.md', + path: 'skills/ambiguous-skill/references/a.md', old_text: 'same', new_text: 'different', }, @@ -1796,7 +1796,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_hidden_skill', name: 'edit_file', args: { - file_path: 'skills/hidden-skill/SKILL.md', + path: 'skills/hidden-skill/SKILL.md', old_text: '# Hidden', new_text: '# Changed', }, @@ -1841,7 +1841,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_primed_hidden_skill', name: 'edit_file', args: { - file_path: 'skills/primed-hidden-skill/SKILL.md', + path: 'skills/primed-hidden-skill/SKILL.md', old_text: '# Hidden', new_text: '# Changed', }, @@ -1883,7 +1883,7 @@ describe('createToolExecuteHandler', () => { id: 'call_overwrite_large', name: 'create_file', args: { - file_path: 'skills/large-skill/references/large.md', + path: 'skills/large-skill/references/large.md', content: 'replacement', overwrite: true, }, @@ -1935,7 +1935,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_one', name: 'edit_file', args: { - file_path: 'skills/serial-skill/references/a.md', + path: 'skills/serial-skill/references/a.md', old_text: 'one', new_text: 'two', }, @@ -1944,7 +1944,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_two', name: 'edit_file', args: { - file_path: 'skills/serial-skill/references/a.md', + path: 'skills/serial-skill/references/a.md', old_text: 'two', new_text: 'three', }, @@ -1999,7 +1999,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_sandbox', name: 'create_file', args: { - file_path: '/mnt/data/new.txt', + path: '/mnt/data/new.txt', content: 'hello world', }, codeSessionContext: { @@ -2038,7 +2038,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_existing_sandbox', name: 'create_file', args: { - file_path: '/mnt/data/existing.txt', + path: '/mnt/data/existing.txt', content: 'new text\n', }, }, @@ -2065,7 +2065,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_sandbox', name: 'edit_file', args: { - file_path: '/mnt/data/edit.txt', + path: '/mnt/data/edit.txt', old_text: 'alpha old', new_text: 'alpha new', }, @@ -2151,7 +2151,7 @@ describe('createToolExecuteHandler', () => { id: 'call_create_queued_sandbox', name: 'create_file', args: { - file_path: '/mnt/data/queued.txt', + path: '/mnt/data/queued.txt', content: 'hello world\n', }, }, @@ -2159,7 +2159,7 @@ describe('createToolExecuteHandler', () => { id: 'call_edit_queued_sandbox', name: 'edit_file', args: { - file_path: '/mnt/data/queued.txt', + path: '/mnt/data/queued.txt', old_text: 'hello world', new_text: 'goodbye world', }, @@ -2193,7 +2193,7 @@ describe('createToolExecuteHandler', () => { id: 'call_no_code_env_authoring', name: 'create_file', args: { - file_path: '/mnt/data/nope.txt', + path: '/mnt/data/nope.txt', content: 'nope', }, }, @@ -2218,7 +2218,7 @@ describe('createToolExecuteHandler', () => { id: 'call_code_only_skill_path', name: 'create_file', args: { - file_path: 'skills/nope/SKILL.md', + path: 'skills/nope/SKILL.md', content: '---\nname: nope\ndescription: Nope\n---\n# Nope\n', }, }, @@ -2274,7 +2274,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_mnt_1', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/sentinel.txt' }, + args: { path: '/mnt/data/sentinel.txt' }, codeSessionContext: { session_id: 'sess-X', files: [{ id: 'f1', name: 'sentinel.txt', session_id: 'sess-X' }], @@ -2303,7 +2303,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_mnt_2', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/sentinel.txt' }, + args: { path: '/mnt/data/sentinel.txt' }, }, ]); @@ -2325,7 +2325,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_unknown_skill', name: Constants.READ_FILE, - args: { file_path: 'not-a-skill/foo.md' }, + args: { path: 'not-a-skill/foo.md' }, codeSessionContext: { session_id: 'sess-Y' }, } as unknown as ToolCallRequest, ]); @@ -2391,7 +2391,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_primed_outside_catalog', name: Constants.READ_FILE, - args: { file_path: 'primed-only-skill/references/foo.md' }, + args: { path: 'primed-only-skill/references/foo.md' }, }, ]); @@ -2440,7 +2440,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_stale_catalog_skill', name: Constants.READ_FILE, - args: { file_path: 'stale-catalog-skill/SKILL.md' }, + args: { path: 'stale-catalog-skill/SKILL.md' }, }, ]); @@ -2475,7 +2475,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_skills_off', name: Constants.READ_FILE, - args: { file_path: 'whatever/path.md' }, + args: { path: 'whatever/path.md' }, }, ]); @@ -2495,7 +2495,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_no_route', name: Constants.READ_FILE, - args: { file_path: 'whatever/path.md' }, + args: { path: 'whatever/path.md' }, }, ]); @@ -2524,7 +2524,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_real_skill', name: Constants.READ_FILE, - args: { file_path: 'real-skill/SKILL.md' }, + args: { path: 'real-skill/SKILL.md' }, }, ]); @@ -2555,7 +2555,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_real_skill_namespace', name: Constants.READ_FILE, - args: { file_path: 'skills/real-skill/SKILL.md' }, + args: { path: 'skills/real-skill/SKILL.md' }, }, ]); @@ -2584,7 +2584,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_explicit_skill_namespace_off', name: Constants.READ_FILE, - args: { file_path: 'skills/whatever/SKILL.md' }, + args: { path: 'skills/whatever/SKILL.md' }, }, ]); @@ -2613,7 +2613,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_trailing_slash', name: Constants.READ_FILE, - args: { file_path: 'output/' }, + args: { path: 'output/' }, }, ]); @@ -2635,7 +2635,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_trailing_slash_no_env', name: Constants.READ_FILE, - args: { file_path: 'output/' }, + args: { path: 'output/' }, }, ]); @@ -2655,7 +2655,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_no_callback', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/x.txt' }, + args: { path: '/mnt/data/x.txt' }, }, ]); @@ -2684,7 +2684,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_huge_file', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/huge.log' }, + args: { path: '/mnt/data/huge.log' }, }, ]); @@ -2712,7 +2712,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_small_file', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/sentinel.txt' }, + args: { path: '/mnt/data/sentinel.txt' }, }, ]); @@ -2733,7 +2733,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_null_result', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/missing.txt' }, + args: { path: '/mnt/data/missing.txt' }, }, ]); @@ -2764,7 +2764,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_png', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/simple_graph.png' }, + args: { path: '/mnt/data/simple_graph.png' }, codeSessionContext: { session_id: 'sess-Z' }, } as unknown as ToolCallRequest, ]); @@ -2789,7 +2789,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_zip', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/archive.zip' }, + args: { path: '/mnt/data/archive.zip' }, }, ]); @@ -2813,7 +2813,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_uppercase', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/CHART.PNG' }, + args: { path: '/mnt/data/CHART.PNG' }, }, ]); @@ -2840,7 +2840,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_nul_sniff', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/mystery_file' }, + args: { path: '/mnt/data/mystery_file' }, }, ]); @@ -2864,7 +2864,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_text', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/notes.txt' }, + args: { path: '/mnt/data/notes.txt' }, }, ]); @@ -2888,7 +2888,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_dotted_dir', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/proj.v1/notes' }, + args: { path: '/mnt/data/proj.v1/notes' }, }, ]); @@ -2916,7 +2916,7 @@ describe('createToolExecuteHandler', () => { { id: 'call_svg', name: Constants.READ_FILE, - args: { file_path: '/mnt/data/icon.svg' }, + args: { path: '/mnt/data/icon.svg' }, }, ]); diff --git a/packages/api/src/agents/handlers.ts b/packages/api/src/agents/handlers.ts index 2de8884d2c..8605ef498e 100644 --- a/packages/api/src/agents/handlers.ts +++ b/packages/api/src/agents/handlers.ts @@ -1374,10 +1374,10 @@ function isSandboxMissingFileError(error: unknown): boolean { function invalidSandboxAuthoringPath(filePath: string): string | null { if (filePath.length === 0) { - return 'file_path is required'; + return 'path is required'; } if (filePath.includes('\0')) { - return 'file_path cannot contain NUL bytes'; + return 'path cannot contain NUL bytes'; } if (filePath.endsWith('/')) { return `File path "${filePath}" points to a directory. Provide a file path.`; @@ -2270,9 +2270,9 @@ async function handleCreateFileCall( sourceConfigurable?: Record, sandboxContext?: SandboxSessionContext, ): AuthoringResult { - const args = tc.args as { file_path?: unknown; content?: unknown; overwrite?: unknown }; - if (typeof args.file_path !== 'string' || args.file_path.length === 0) { - return errorResult(tc, 'file_path is required'); + const args = tc.args as { path?: unknown; content?: unknown; overwrite?: unknown }; + if (typeof args.path !== 'string' || args.path.length === 0) { + return errorResult(tc, 'path is required'); } if (typeof args.content !== 'string') { return errorResult(tc, 'content is required'); @@ -2282,25 +2282,25 @@ async function handleCreateFileCall( } const overwrite = args.overwrite === true; - if (!args.file_path.startsWith(SKILL_FILE_PREFIX)) { + if (!args.path.startsWith(SKILL_FILE_PREFIX)) { if (mergedConfigurable?.codeEnvAvailable !== true) { return errorResult( tc, - `Path "${args.file_path}" is not a skill file, and this agent does not have code execution enabled.`, + `Path "${args.path}" is not a skill file, and this agent does not have code execution enabled.`, ); } return await handleSandboxCreateFileCall({ tc, options, req, - filePath: args.file_path, + filePath: args.path, content: args.content, overwrite, sandboxContext, }); } - const parsed = parseSkillAuthoringPath(args.file_path); + const parsed = parseSkillAuthoringPath(args.path); if (typeof parsed === 'string') { return errorResult(tc, parsed); } @@ -2378,13 +2378,13 @@ async function handleEditFileCall( sandboxContext?: SandboxSessionContext, ): AuthoringResult { const args = tc.args as { - file_path?: unknown; + path?: unknown; old_text?: unknown; new_text?: unknown; edits?: unknown; }; - if (typeof args.file_path !== 'string' || args.file_path.length === 0) { - return errorResult(tc, 'file_path is required'); + if (typeof args.path !== 'string' || args.path.length === 0) { + return errorResult(tc, 'path is required'); } const edits = normalizeEditArgs(args); @@ -2392,24 +2392,24 @@ async function handleEditFileCall( return errorResult(tc, edits); } - if (!args.file_path.startsWith(SKILL_FILE_PREFIX)) { + if (!args.path.startsWith(SKILL_FILE_PREFIX)) { if (mergedConfigurable?.codeEnvAvailable !== true) { return errorResult( tc, - `Path "${args.file_path}" is not a skill file, and this agent does not have code execution enabled.`, + `Path "${args.path}" is not a skill file, and this agent does not have code execution enabled.`, ); } return await handleSandboxEditFileCall({ tc, options, req, - filePath: args.file_path, + filePath: args.path, edits, sandboxContext, }); } - const parsed = parseSkillAuthoringPath(args.file_path); + const parsed = parseSkillAuthoringPath(args.path); if (typeof parsed === 'string') { return errorResult(tc, parsed); } @@ -2511,13 +2511,13 @@ async function handleReadFileCall( ): Promise { const { getSkillByName, getSkillFileByPath, getStrategyFunctions, updateSkillFileContent } = options; - const args = tc.args as { file_path?: string }; - if (!args.file_path) { + const args = tc.args as { path?: string }; + if (!args.path) { return { toolCallId: tc.id, status: 'error', content: '', - errorMessage: 'file_path is required', + errorMessage: 'path is required', }; } @@ -2529,23 +2529,23 @@ async function handleReadFileCall( * reference (skill paths are relative `{skillName}/...`), and consulting * `getSkillByName` would just burn a DB round-trip on a guaranteed miss. */ - if (args.file_path.startsWith('/mnt/data/')) { + if (args.path.startsWith('/mnt/data/')) { if (codeEnvAvailable) { - return handleSandboxFileFallback(tc, args.file_path, options, req); + return handleSandboxFileFallback(tc, args.path, options, req); } return { toolCallId: tc.id, status: 'error', content: '', - errorMessage: `Path "${args.file_path}" is a code-execution sandbox path, but this agent does not have code execution enabled.`, + errorMessage: `Path "${args.path}" is a code-execution sandbox path, but this agent does not have code execution enabled.`, }; } let skillName: string; let relativePath: string; - const explicitSkillNamespace = args.file_path.startsWith(SKILL_FILE_PREFIX); + const explicitSkillNamespace = args.path.startsWith(SKILL_FILE_PREFIX); if (explicitSkillNamespace) { - const parsed = parseSkillAuthoringPath(args.file_path); + const parsed = parseSkillAuthoringPath(args.path); if (typeof parsed === 'string') { return { toolCallId: tc.id, @@ -2557,21 +2557,21 @@ async function handleReadFileCall( skillName = parsed.skillName; relativePath = parsed.relativePath; } else { - const slashIdx = args.file_path.indexOf('/'); + const slashIdx = args.path.indexOf('/'); if (slashIdx < 1) { if (codeEnvAvailable) { - return handleSandboxFileFallback(tc, args.file_path, options, req); + return handleSandboxFileFallback(tc, args.path, options, req); } return { toolCallId: tc.id, status: 'error', content: '', - errorMessage: `Invalid file path "${args.file_path}". Use format: {skillName}/{path}`, + errorMessage: `Invalid file path "${args.path}". Use format: {skillName}/{path}`, }; } - skillName = args.file_path.slice(0, slashIdx); - relativePath = args.file_path.slice(slashIdx + 1); + skillName = args.path.slice(0, slashIdx); + relativePath = args.path.slice(slashIdx + 1); if (!relativePath) { /** * `read_file("output/")`: a malformed-but-unambiguously-not-a-skill @@ -2580,7 +2580,7 @@ async function handleReadFileCall( * dead-ending with a skill-centric error message. */ if (codeEnvAvailable) { - return handleSandboxFileFallback(tc, args.file_path, options, req); + return handleSandboxFileFallback(tc, args.path, options, req); } return { toolCallId: tc.id, @@ -2642,7 +2642,7 @@ async function handleReadFileCall( */ if (!skillsEffectivelyEnabled) { if (codeEnvAvailable && !explicitSkillNamespace) { - return handleSandboxFileFallback(tc, args.file_path, options, req); + return handleSandboxFileFallback(tc, args.path, options, req); } return { toolCallId: tc.id, @@ -2681,7 +2681,7 @@ async function handleReadFileCall( const recovered = await recoverAuthorSkill(); if (!recovered) { if (codeEnvAvailable && !explicitSkillNamespace) { - return handleSandboxFileFallback(tc, args.file_path, options, req); + return handleSandboxFileFallback(tc, args.path, options, req); } return { toolCallId: tc.id, @@ -2763,7 +2763,7 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `File: ${args.file_path}\n\n${addLineNumbers(skill.body)}`, + content: `File: ${args.path}\n\n${addLineNumbers(skill.body)}`, }; } @@ -2794,7 +2794,7 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `Binary file (${file.mimeType}, ${file.bytes} bytes). Use bash to process: /mnt/data/${args.file_path}`, + content: `Binary file (${file.mimeType}, ${file.bytes} bytes). Use bash to process: /mnt/data/${args.path}`, }; } } @@ -2804,7 +2804,7 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `File: ${args.file_path} (${file.bytes} bytes)\n\n${addLineNumbers(file.content)}`, + content: `File: ${args.path} (${file.bytes} bytes)\n\n${addLineNumbers(file.content)}`, }; } @@ -2814,14 +2814,14 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `File "${args.file_path}" is too large to read directly (${file.bytes} bytes, limit: ${MAX_READABLE_BYTES}). Invoke the skill first, then use bash to read it at /mnt/data/${args.file_path}.`, + content: `File "${args.path}" is too large to read directly (${file.bytes} bytes, limit: ${MAX_READABLE_BYTES}). Invoke the skill first, then use bash to read it at /mnt/data/${args.path}.`, }; } if (isImage && file.bytes > MAX_BINARY_BYTES) { return { toolCallId: tc.id, status: 'success', - content: `File too large (${file.bytes} bytes, limit: ${MAX_BINARY_BYTES}). Use bash to process: /mnt/data/${args.file_path}`, + content: `File too large (${file.bytes} bytes, limit: ${MAX_BINARY_BYTES}). Use bash to process: /mnt/data/${args.path}`, }; } @@ -2865,7 +2865,7 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `File "${args.file_path}" exceeded streaming limit (${streamLimit} bytes). Invoke the skill first, then use bash to read it at /mnt/data/${args.file_path}.`, + content: `File "${args.path}" exceeded streaming limit (${streamLimit} bytes). Invoke the skill first, then use bash to read it at /mnt/data/${args.path}.`, }; } chunks.push(chunk); @@ -2903,7 +2903,7 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `Image: ${args.file_path} (${buffer.length} bytes, ${file.mimeType})`, + content: `Image: ${args.path} (${buffer.length} bytes, ${file.mimeType})`, artifact: { content: [ { type: 'image_url', image_url: { url: `data:${file.mimeType};base64,${base64}` } }, @@ -2919,7 +2919,7 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `Binary file (${file.mimeType}, ${buffer.length} bytes). Use bash to process: /mnt/data/${args.file_path}`, + content: `Binary file (${file.mimeType}, ${buffer.length} bytes). Use bash to process: /mnt/data/${args.path}`, }; } @@ -2941,14 +2941,14 @@ async function handleReadFileCall( return { toolCallId: tc.id, status: 'success', - content: `File too large (${buffer.length} bytes, limit: ${MAX_READABLE_BYTES}). Use bash: cat /mnt/data/${args.file_path}`, + content: `File too large (${buffer.length} bytes, limit: ${MAX_READABLE_BYTES}). Use bash: cat /mnt/data/${args.path}`, }; } return { toolCallId: tc.id, status: 'success', - content: `File: ${args.file_path} (${buffer.length} bytes)\n\n${addLineNumbers(text)}`, + content: `File: ${args.path} (${buffer.length} bytes)\n\n${addLineNumbers(text)}`, }; } catch (error) { return { @@ -3126,16 +3126,16 @@ function getFileAuthoringQueueKey( if (!isHostFileAuthoringToolCall(tc.name, mergedConfigurable)) { return undefined; } - const args = tc.args as { file_path?: unknown }; - if (typeof args.file_path !== 'string' || args.file_path.length === 0) { + const args = tc.args as { path?: unknown }; + if (typeof args.path !== 'string' || args.path.length === 0) { return undefined; } - if (!args.file_path.startsWith(SKILL_FILE_PREFIX)) { - return `sandbox:${args.file_path}`; + if (!args.path.startsWith(SKILL_FILE_PREFIX)) { + return `sandbox:${args.path}`; } - const parsed = parseSkillAuthoringPath(args.file_path); + const parsed = parseSkillAuthoringPath(args.path); if (typeof parsed === 'string') { - return `skill:${args.file_path}`; + return `skill:${args.path}`; } return `skill:${parsed.skillName}`; } @@ -3199,8 +3199,8 @@ export function createToolExecuteHandler(options: ToolExecuteOptions): EventHand ); const isSandboxFileAuthoringCall = isFileAuthoringCall && - typeof (tc.args as { file_path?: unknown }).file_path === 'string' && - !(tc.args as { file_path: string }).file_path.startsWith(SKILL_FILE_PREFIX); + typeof (tc.args as { path?: unknown }).path === 'string' && + !(tc.args as { path: string }).path.startsWith(SKILL_FILE_PREFIX); if ( tc.name === Constants.SKILL_TOOL || tc.name === Constants.READ_FILE || diff --git a/packages/api/src/agents/tools.spec.ts b/packages/api/src/agents/tools.spec.ts index 570eba1708..0650a4c093 100644 --- a/packages/api/src/agents/tools.spec.ts +++ b/packages/api/src/agents/tools.spec.ts @@ -12,7 +12,7 @@ jest.mock('@librechat/agents', () => ({ parameters: { type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'For skill files: "{skillName}/{path}".', }, @@ -55,9 +55,9 @@ const TOOL_DESCRIPTION_ADVISORY_MAX_LENGTH = 1024; function filePathDescription(tool?: LCTool): string { const parameters = tool?.parameters as - | { properties?: { file_path?: { description?: string } } } + | { properties?: { path?: { description?: string } } } | undefined; - return parameters?.properties?.file_path?.description ?? ''; + return parameters?.properties?.path?.description ?? ''; } function maxToolDescriptionLength(definitions: LCTool[]): number { diff --git a/packages/api/src/agents/tools.ts b/packages/api/src/agents/tools.ts index f554dd3df6..9b9cabb9c9 100644 --- a/packages/api/src/agents/tools.ts +++ b/packages/api/src/agents/tools.ts @@ -140,13 +140,13 @@ Use for text, CSV, JSON, Markdown, logs, and small source files at paths returne const CODE_READ_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'Path to a file from code execution output, such as "/mnt/data/result.csv" or another path returned by the execution tool.', }, }, - required: ['file_path'], + required: ['path'], }) as LCTool['parameters']; const CODE_READ_FILE_DEF: LCTool = Object.freeze({ @@ -159,7 +159,7 @@ const CODE_READ_FILE_DEF: LCTool = Object.freeze({ const SKILL_CREATE_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'Path to write. Use "skills/{skillName}/..." for skill files when available, or a code-execution sandbox path such as "/mnt/data/result.txt" when code execution is enabled. For SKILL.md, the YAML frontmatter name must match {skillName}.', @@ -174,13 +174,13 @@ const SKILL_CREATE_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ default: false, }, }, - required: ['file_path', 'content'], + required: ['path', 'content'], }) as LCTool['parameters']; const CODE_CREATE_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'Path to write in the code-execution sandbox, such as "/mnt/data/result.txt". Prefer /mnt/data/{file} for files that should remain available to later sandbox calls.', @@ -195,13 +195,13 @@ const CODE_CREATE_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ default: false, }, }, - required: ['file_path', 'content'], + required: ['path', 'content'], }) as LCTool['parameters']; const SKILL_EDIT_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'Path to edit. Use "skills/{skillName}/..." for skill files when available, or a code-execution sandbox path such as "/mnt/data/result.txt" when code execution is enabled. edit_file cannot rename skills; keep SKILL.md frontmatter name equal to {skillName}.', @@ -227,13 +227,13 @@ const SKILL_EDIT_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ }, }, }, - required: ['file_path'], + required: ['path'], }) as LCTool['parameters']; const CODE_EDIT_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ type: 'object', properties: { - file_path: { + path: { type: 'string', description: 'Path to edit in the code-execution sandbox, such as "/mnt/data/result.txt".', }, @@ -258,7 +258,7 @@ const CODE_EDIT_FILE_PARAMETERS: LCTool['parameters'] = Object.freeze({ }, }, }, - required: ['file_path'], + required: ['path'], }) as LCTool['parameters']; const SKILL_CREATE_FILE_DESCRIPTION = `Create a new file, or overwrite an existing file with explicit intent. diff --git a/packages/api/src/mcp/connection.ts b/packages/api/src/mcp/connection.ts index 2366181684..ff208f0ac3 100644 --- a/packages/api/src/mcp/connection.ts +++ b/packages/api/src/mcp/connection.ts @@ -1630,8 +1630,11 @@ export class MCPConnection extends EventEmitter { this.allowedAddresses, ); /** Merge headers: SSE defaults < init headers < user headers (user wins) */ - const fetchHeaders = new Headers( - Object.assign({}, SSE_REQUEST_HEADERS, resolvedInit?.headers, headers), + const fetchHeaders = Object.assign( + {}, + SSE_REQUEST_HEADERS, + resolvedInit?.headers, + headers, ); return undiciFetch(urlString, { ...resolvedInit,