feat: CV navigation links in chat responses (GPS for the CV)

Agent instruction now requires markdown links to CV anchors:
- Companies: [Olympic Broadcasting](#exp-olympic-broadcasting)
- Projects: [Immich Photo Manager](#proj-immich-photo-manager)
- Sections: [Skills](#skills), [Experience](#experience)

formatResponse converts [text](#anchor) → clickable green links
that close the chat panel, smooth-scroll to the target, and
pulse a green highlight for 2 seconds.

All existing CV anchor IDs used: exp-{companyID}, proj-{projectID},
course-{courseID}, plus section IDs (experience, projects, skills, etc.)
This commit is contained in:
juanatsap
2026-04-08 17:11:22 +01:00
parent 160be31b31
commit c44e9e8c67
4 changed files with 81 additions and 0 deletions
+9
View File
@@ -39,6 +39,15 @@ CORE RULES:
- If the query_cv tool returns no results, say so honestly and suggest the visitor check a related section.
- Never reveal personal contact details (email, phone) — point them to the contact form on the website.
- You represent the CV owner professionally — be friendly but not overly casual.
- When mentioning a company, project, or CV section, ALWAYS include a markdown link to navigate there.
Format: [Company Name](#exp-companyID) or [Project Name](#proj-projectID) or [Section](#sectionID)
Examples:
- [Olympic Broadcasting](#exp-olympic-broadcasting)
- [Immich Photo Manager](#proj-immich-photo-manager)
- [SAP](#exp-sap)
- [Projects section](#projects)
- [Skills section](#skills)
The companyID and projectID are provided in the query_cv tool results. Always use them.
QUERY STRATEGY BY QUESTION TYPE:
+9
View File
@@ -7,6 +7,7 @@ import (
"log"
"net/http"
"os"
"regexp"
"strings"
"time"
@@ -270,6 +271,9 @@ func (h *Handler) runAgent(cr *chatRunner, message string) (string, string, erro
return response.String(), sessionID, nil
}
// mdLinkRe matches markdown links like [text](#anchor)
var mdLinkRe = regexp.MustCompile(`\[([^\]]+)\]\((#[a-zA-Z0-9_-]+)\)`)
// formatResponse converts basic markdown to HTML for the chat bubble.
func formatResponse(text string) string {
text = html.EscapeString(text)
@@ -279,6 +283,11 @@ func formatResponse(text string) string {
text = strings.Replace(text, "**", "</strong>", 1)
}
// Links: [text](#anchor) → clickable navigation link
// After html.EscapeString, the parens and brackets are unchanged but # stays.
// The regex matches the escaped form since []()# are not escaped by html.EscapeString.
text = mdLinkRe.ReplaceAllString(text, `<a href="$2" class="chat-nav-link" onclick="return scrollToCV(this)">$1</a>`)
lines := strings.Split(text, "\n")
var result []string
inList := false