From ed8907a948fd14880a6a49d13f0402966a13bd1d Mon Sep 17 00:00:00 2001 From: afterrburn Date: Fri, 23 Jan 2026 07:27:55 -0700 Subject: [PATCH 1/2] bug(tools.ts): fix unsafe URL error in RAG search links Extract documentPathToUrl to shared utility and apply URL transformation in askDocsAgentTool to ensure document paths are converted to valid URLs with leading slashes. Co-Authored-By: Claude Opus 4.5 --- doc-agents/src/agent/agent_pulse/tools.ts | 8 ++++++ doc-agents/src/api/doc-qa/route.ts | 33 +---------------------- doc-agents/src/utils/url.ts | 31 +++++++++++++++++++++ doc-agents/tsconfig.json | 3 ++- 4 files changed, 42 insertions(+), 33 deletions(-) create mode 100644 doc-agents/src/utils/url.ts diff --git a/doc-agents/src/agent/agent_pulse/tools.ts b/doc-agents/src/agent/agent_pulse/tools.ts index 3e24ca89..2efa844b 100644 --- a/doc-agents/src/agent/agent_pulse/tools.ts +++ b/doc-agents/src/agent/agent_pulse/tools.ts @@ -4,6 +4,7 @@ import { getTutorialMeta } from './tutorial'; import docQAAgent from '@agent/doc_qa'; import type { Action } from './types'; import { ActionType } from './types'; +import { documentPathToUrl } from '@utils/url'; interface ToolState { action: Action | null; @@ -60,6 +61,13 @@ export async function createTools(state: ToolState, agentContext: any) { const response = await docQAAgent.run({ message: query, }); + // Transform document URLs from raw paths to proper URLs + if (response.documents && Array.isArray(response.documents)) { + response.documents = response.documents.map((doc) => ({ + ...doc, + url: documentPathToUrl(doc.url), + })); + } return response; } catch (error) { agentContext.logger.error('Error calling doc-qa agent: %s', error); diff --git a/doc-agents/src/api/doc-qa/route.ts b/doc-agents/src/api/doc-qa/route.ts index 2d476460..5ae09fd7 100644 --- a/doc-agents/src/api/doc-qa/route.ts +++ b/doc-agents/src/api/doc-qa/route.ts @@ -1,41 +1,10 @@ import { createRouter } from '@agentuity/runtime'; import docQAAgent from '@agent/doc_qa'; import { bearerTokenAuth } from '@middleware/auth'; +import { documentPathToUrl } from '@utils/url'; const router = createRouter(); -/** - * Transforms a document path (e.g., "Agents/index.mdx") to a proper URL (e.g., "/Agents") - */ -function documentPathToUrl(docPath: string): string { - // Remove the .md or .mdx extension before any # symbol - const path = docPath.replace(/\.mdx?(?=#|$)/, ''); - - // Split path and hash (if any) - const [basePath = '', hash] = path.split('#'); - - // Split the base path into segments - const segments = basePath.split('/').filter(Boolean); - - // If the last segment is 'index', remove it - if ( - segments.length > 0 && - segments[segments.length - 1]?.toLowerCase() === 'index' - ) { - segments.pop(); - } - - // Reconstruct the path - let url = `/${segments.join('/')}`; - if (url === '/') { - url = '/'; - } - if (hash) { - url += `#${hash}`; - } - return url; -} - // POST /api/doc-qa - Answer questions about documentation (bearer token protected, no user context) router.post('/', bearerTokenAuth, docQAAgent.validator(), async (c) => { const data = c.req.valid('json'); diff --git a/doc-agents/src/utils/url.ts b/doc-agents/src/utils/url.ts new file mode 100644 index 00000000..40814f5b --- /dev/null +++ b/doc-agents/src/utils/url.ts @@ -0,0 +1,31 @@ +/** + * Transforms a document path (e.g., "Get-Started/quickstart.mdx#7-deploy") to a proper URL (e.g., "/Get-Started/quickstart#7-deploy") + */ +export function documentPathToUrl(docPath: string): string { + // Remove the .md or .mdx extension before any # symbol + const path = docPath.replace(/\.mdx?(?=#|$)/, ''); + + // Split path and hash (if any) + const [basePath = '', hash] = path.split('#'); + + // Split the base path into segments + const segments = basePath.split('/').filter(Boolean); + + // If the last segment is 'index', remove it + if ( + segments.length > 0 && + segments[segments.length - 1]?.toLowerCase() === 'index' + ) { + segments.pop(); + } + + // Reconstruct the path with leading slash + let url = `/${segments.join('/')}`; + if (url === '/') { + url = '/'; + } + if (hash) { + url += `#${hash}`; + } + return url; +} diff --git a/doc-agents/tsconfig.json b/doc-agents/tsconfig.json index 7f774deb..33afcbdd 100644 --- a/doc-agents/tsconfig.json +++ b/doc-agents/tsconfig.json @@ -21,7 +21,8 @@ "paths": { "@agent/*": ["./src/agent/*"], "@api/*": ["./src/api/*"], - "@middleware/*": ["./src/middleware/*"] + "@middleware/*": ["./src/middleware/*"], + "@utils/*": ["./src/utils/*"] } }, "include": ["src/**/*", "app.ts"] From bb657b7ef01ffc091cf9abdc347ddeb2827f2c96 Mon Sep 17 00:00:00 2001 From: Seng Rith <50646727+afterrburn@users.noreply.github.com> Date: Fri, 23 Jan 2026 11:14:38 -0700 Subject: [PATCH 2/2] Update doc-agents/src/utils/url.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Signed-off-by: Seng Rith <50646727+afterrburn@users.noreply.github.com> --- doc-agents/src/utils/url.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc-agents/src/utils/url.ts b/doc-agents/src/utils/url.ts index 40814f5b..9e29d469 100644 --- a/doc-agents/src/utils/url.ts +++ b/doc-agents/src/utils/url.ts @@ -1,13 +1,15 @@ /** * Transforms a document path (e.g., "Get-Started/quickstart.mdx#7-deploy") to a proper URL (e.g., "/Get-Started/quickstart#7-deploy") */ -export function documentPathToUrl(docPath: string): string { +export function documentPathToUrl(docPath?: string | null): string { + if (!docPath) { + return '/'; + } // Remove the .md or .mdx extension before any # symbol const path = docPath.replace(/\.mdx?(?=#|$)/, ''); // Split path and hash (if any) const [basePath = '', hash] = path.split('#'); - // Split the base path into segments const segments = basePath.split('/').filter(Boolean);