From 78fdebf2262b586b872856e479e9447f3a3c0d9d Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Mon, 15 Jun 2026 01:54:58 +0200 Subject: [PATCH] feat(api): add formatLocationToolResult helper --- packages/api/src/agents/index.ts | 1 + packages/api/src/agents/location.spec.ts | 47 ++++++++++++++++++++++++ packages/api/src/agents/location.ts | 43 ++++++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 packages/api/src/agents/location.spec.ts create mode 100644 packages/api/src/agents/location.ts diff --git a/packages/api/src/agents/index.ts b/packages/api/src/agents/index.ts index 14e0f480fd..24da1eafef 100644 --- a/packages/api/src/agents/index.ts +++ b/packages/api/src/agents/index.ts @@ -9,6 +9,7 @@ export * from './edges'; export * from './handlers'; export * from './initialize'; export * from './legacy'; +export * from './location'; export * from './memory'; export * from './orphans'; export * from './migration'; diff --git a/packages/api/src/agents/location.spec.ts b/packages/api/src/agents/location.spec.ts new file mode 100644 index 0000000000..70fc1fda12 --- /dev/null +++ b/packages/api/src/agents/location.spec.ts @@ -0,0 +1,47 @@ +import { formatLocationToolResult } from './location'; + +describe('formatLocationToolResult', () => { + it('reports a disabled message when the feature is off', () => { + const result = formatLocationToolResult( + { enabled: true, place: 'Paris' }, + { featureEnabled: false }, + ); + expect(result).toMatch(/disabled/i); + }); + + it('reports not-shared when the user has not opted in', () => { + const result = formatLocationToolResult(undefined, { featureEnabled: true }); + expect(result).toMatch(/has not shared/i); + }); + + it('reports not-shared when enabled is false', () => { + const result = formatLocationToolResult({ enabled: false }, { featureEnabled: true }); + expect(result).toMatch(/has not shared/i); + }); + + it('prefers the manual override as the place', () => { + const result = formatLocationToolResult( + { enabled: true, source: 'manual', manual: 'Tokyo, Japan', place: 'ignored' }, + { featureEnabled: true }, + ); + expect(result).toContain('Tokyo, Japan'); + expect(result).not.toContain('ignored'); + }); + + it('includes place, coordinates, and timezone for device location', () => { + const result = formatLocationToolResult( + { + enabled: true, + source: 'auto', + place: 'Paris, Île-de-France, France', + coordinates: { latitude: 48.85, longitude: 2.35 }, + timezone: 'Europe/Paris', + }, + { featureEnabled: true }, + ); + expect(result).toContain('Paris, Île-de-France, France'); + expect(result).toContain('48.85'); + expect(result).toContain('2.35'); + expect(result).toContain('Europe/Paris'); + }); +}); diff --git a/packages/api/src/agents/location.ts b/packages/api/src/agents/location.ts new file mode 100644 index 0000000000..d3f17e4594 --- /dev/null +++ b/packages/api/src/agents/location.ts @@ -0,0 +1,43 @@ +import type { TUserLocation } from 'librechat-data-provider'; + +export interface FormatLocationOptions { + /** Resolved admin feature flag (`librechat.yaml` location.enabled) */ + featureEnabled: boolean; +} + +const NOT_SHARED = 'The user has not shared their location.'; +const DISABLED = 'The location feature is disabled by the administrator.'; + +/** + * Formats the user's stored location into a concise, model-friendly string. + * Returns a graceful message when the feature is disabled or no location is shared. + */ +export function formatLocationToolResult( + location: TUserLocation | undefined, + options: FormatLocationOptions, +): string { + if (!options.featureEnabled) { + return DISABLED; + } + if (!location || location.enabled !== true) { + return NOT_SHARED; + } + + const place = location.manual?.trim() || location.place?.trim(); + const parts: string[] = []; + if (place) { + parts.push(`Location: ${place}`); + } + if (location.coordinates) { + const { latitude, longitude } = location.coordinates; + parts.push(`Coordinates: ${latitude}, ${longitude}`); + } + if (location.timezone) { + parts.push(`Timezone: ${location.timezone}`); + } + + if (parts.length === 0) { + return NOT_SHARED; + } + return parts.join('\n'); +}