Skip to content

feat(platform): user context template variables for agent prompts#835

Merged
larryro merged 3 commits into
mainfrom
feat/user-context-template-variables
Mar 23, 2026
Merged

feat(platform): user context template variables for agent prompts#835
larryro merged 3 commits into
mainfrom
feat/user-context-template-variables

Conversation

@larryro
Copy link
Copy Markdown
Collaborator

@larryro larryro commented Mar 23, 2026

Summary

  • Passes user environment context (timezone, language, coordinates, location) from the browser through the entire chat pipeline to agent system prompt template resolution
  • Adds new template variables: {{user.timezone}}, {{user.language}}, {{user.coordinates}}, {{user.location}}, and {{user_instruction}}
  • The {{user_instruction}} variable generates a complete user context block including name, email, role, organization, timezone, language, location, and current time

Test plan

  • Verify useUserContext hook returns correct browser timezone and language
  • Confirm user context is passed through useSendMessagechatWithAgent mutation → startAgentChatgenerateAgentResponse
  • Test individual template variables ({{user.timezone}}, etc.) resolve correctly in agent instructions
  • Test {{user_instruction}} produces a well-formatted user context block
  • Verify no regressions when userContext is undefined (optional field)
  • Test that fetchMemberRole correctly retrieves the user's organization role

Summary by CodeRabbit

  • New Features
    • Chat agents now have access to user context information including timezone, language, and geographic location. This enables the system to provide more personalized assistance that is aware of the user's time zone and location.
    • User location and timezone data are automatically collected when available, allowing agents to offer contextually relevant guidance and time-aware information.

…ate variables

Add user environment context (timezone, language, coordinates, location) from
the browser to the agent system prompt template resolution. Introduces
{{user.timezone}}, {{user.language}}, {{user.coordinates}}, {{user.location}},
and {{user_instruction}} template variables. The user_instruction variable
generates a complete user context block including name, email, role, org,
timezone, language, location, and current time.
Copy link
Copy Markdown

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

This PR adds user context collection and propagation throughout the chat system. A new useUserContext hook captures user timezone, language, geolocation coordinates, and reverse-geocoded location from the browser. This context is then passed through the chat message pipeline—from the frontend chat interface, through the useSendMessage hook, via Convex mutations and internal actions, to the backend's template variable resolution layer. The backend integrates this context into template variable resolution, enabling new variables like {{user.timezone}}, {{user.language}}, {{user.coordinates}}, {{user.location}}, and a composite {{user_instruction}} block to be used in agent instructions. User email and member role are fetched on-demand when referenced in instructions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding user context template variables for agent prompts, which is the core objective of this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/user-context-template-variables

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@services/platform/app/features/chat/hooks/use-user-context.ts`:
- Around line 74-115: Add a short comment near the useEffect/getCurrentPosition
block noting that coordinates are included in prompts sent to the LLM, then
reduce precision before storing/sending by rounding latitude/longitude (e.g., to
2 decimal places) prior to building coords, calling setLocation, and persisting
to localStorage (references: useEffect, navigator.geolocation.getCurrentPosition
callback, setLocation, LOCATION_CACHE_KEY, getCachedLocation, isNearby); ensure
isNearby still compares with the same rounded precision or adjust it accordingly
so cached proximity checks remain consistent.
- Around line 90-92: The fetch call in use-user-context.ts that calls Nominatim
(`fetch(`https://nominatim.openstreetmap.org/reverse?...`)`) lacks required
headers; update the request in the function where reverse geocoding is performed
to include a proper User-Agent (or Referer) header (ideally including your app
name and contact/email) by passing a second argument to fetch with a headers
object (e.g., headers: { 'User-Agent': 'MyApp/1.0 (contact@example.com)' } ) so
the Nominatim API compliance requirement is met and requests aren't blocked or
rate-limited.

In `@services/platform/convex/lib/agent_response/resolve_template_variables.ts`:
- Line 192: The assignment userRole: memberRole ?? undefined is redundant
because memberRole is already typed string | undefined; update the object in
resolve_template_variables (the location setting userRole) to directly use
userRole: memberRole (remove the `?? undefined`), ensuring no behavior change
and simplifying the code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 91db8128-ba74-4a69-a674-9c3a227a8c02

📥 Commits

Reviewing files that changed from the base of the PR and between 7966de8 and 4cc38ba.

📒 Files selected for processing (9)
  • services/platform/app/features/chat/components/chat-interface.tsx
  • services/platform/app/features/chat/hooks/use-send-message.ts
  • services/platform/app/features/chat/hooks/use-user-context.ts
  • services/platform/convex/custom_agents/unified_chat.ts
  • services/platform/convex/lib/agent_chat/internal_actions.ts
  • services/platform/convex/lib/agent_chat/start_agent_chat.ts
  • services/platform/convex/lib/agent_response/generate_response.ts
  • services/platform/convex/lib/agent_response/resolve_template_variables.ts
  • services/platform/convex/lib/agent_response/types.ts

Comment on lines +74 to +115
useEffect(() => {
if (!navigator.geolocation) return;

navigator.geolocation.getCurrentPosition(
async (pos) => {
const { latitude: lat, longitude: lng } = pos.coords;
const coords = `${lat}, ${lng}`;
const cached = getCachedLocation();

if (cached && isNearby(lat, lng, cached)) {
setLocation({ coordinates: coords, address: cached.address });
return;
}

setLocation({ coordinates: coords });
try {
const res = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&zoom=10`,
);
const data = await res.json();
const address =
typeof data.display_name === 'string'
? data.display_name
: undefined;
const result = { coordinates: coords, address };
setLocation(result);
localStorage.setItem(
LOCATION_CACHE_KEY,
JSON.stringify({ lat, lng, ...result }),
);
} catch {
localStorage.setItem(
LOCATION_CACHE_KEY,
JSON.stringify({ lat, lng, coordinates: coords }),
);
}
},
() => {
// User denied or geolocation unavailable
},
);
}, []);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider privacy implications of precise geolocation.

The hook requests high-accuracy geolocation (getCurrentPosition defaults to enableHighAccuracy: false, but still provides precise coordinates) and sends these coordinates to the backend where they're included in LLM prompts. While this enables useful location-aware features, consider:

  1. Adding a comment documenting that coordinates flow to the LLM
  2. Using coarser coordinates (e.g., rounding to 2 decimal places ~1km precision) before sending to backend

This is a privacy-by-design consideration rather than a blocking issue.

💡 Optional: Round coordinates for privacy
       const { latitude: lat, longitude: lng } = pos.coords;
-      const coords = `${lat}, ${lng}`;
+      // Round to ~1km precision for privacy
+      const roundedLat = Math.round(lat * 100) / 100;
+      const roundedLng = Math.round(lng * 100) / 100;
+      const coords = `${roundedLat}, ${roundedLng}`;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/chat/hooks/use-user-context.ts` around lines
74 - 115, Add a short comment near the useEffect/getCurrentPosition block noting
that coordinates are included in prompts sent to the LLM, then reduce precision
before storing/sending by rounding latitude/longitude (e.g., to 2 decimal
places) prior to building coords, calling setLocation, and persisting to
localStorage (references: useEffect, navigator.geolocation.getCurrentPosition
callback, setLocation, LOCATION_CACHE_KEY, getCachedLocation, isNearby); ensure
isNearby still compares with the same rounded precision or adjust it accordingly
so cached proximity checks remain consistent.

Comment on lines +90 to +92
const res = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&zoom=10`,
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

OpenStreetMap Nominatim usage policy User-Agent requirement

💡 Result:

OpenStreetMap’s public Nominatim instance (nominatim.openstreetmap.org) requires that every request include a valid HTTP Referer or a custom User-Agent header that identifies your applicationgeneric/stock User-Agents set by common HTTP libraries are not acceptable (and may lead to blocking). (operations.osmfoundation.org)

This requirement is part of the Nominatim Usage Policy for the public service (it does not automatically apply to Nominatim instances you run yourself or that third parties run). (operations.osmfoundation.org)

Citations:


Add User-Agent header for Nominatim API compliance.

OpenStreetMap's public Nominatim API requires requests to include a valid Referer or User-Agent header. Without it, requests may be blocked or rate-limited.

Proposed fix
          const res = await fetch(
            `https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&zoom=10`,
+           {
+             headers: {
+               'User-Agent': 'TalePlatform/1.0 (https://tale-project.io)',
+             },
+           },
          );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const res = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&zoom=10`,
);
const res = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=json&zoom=10`,
{
headers: {
'User-Agent': 'TalePlatform/1.0 (https://tale-project.io)',
},
},
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/app/features/chat/hooks/use-user-context.ts` around lines
90 - 92, The fetch call in use-user-context.ts that calls Nominatim
(`fetch(`https://nominatim.openstreetmap.org/reverse?...`)`) lacks required
headers; update the request in the function where reverse geocoding is performed
to include a proper User-Agent (or Referer) header (ideally including your app
name and contact/email) by passing a second argument to fetch with a headers
object (e.g., headers: { 'User-Agent': 'MyApp/1.0 (contact@example.com)' } ) so
the Nominatim API compliance requirement is met and requests aren't blocked or
rate-limited.

organizationName: orgResult?.name,
userName: userResult?.name,
userEmail: needsUserEmail ? userResult?.email : undefined,
userRole: memberRole ?? undefined,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Minor: Redundant nullish coalescing.

memberRole is already typed as string | undefined, so ?? undefined is a no-op.

Suggested simplification
-    userRole: memberRole ?? undefined,
+    userRole: memberRole,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
userRole: memberRole ?? undefined,
userRole: memberRole,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/platform/convex/lib/agent_response/resolve_template_variables.ts` at
line 192, The assignment userRole: memberRole ?? undefined is redundant because
memberRole is already typed string | undefined; update the object in
resolve_template_variables (the location setting userRole) to directly use
userRole: memberRole (remove the `?? undefined`), ensuring no behavior change
and simplifying the code.

larryro added 2 commits March 23, 2026 15:22
…rofile to workflow LLM steps

Rename the template variable {{humanInputContext}} → {{userAnswers}} for clarity,
and introduce {{userProfile}} which injects user identity context (name, email,
role, organization) into workflow LLM prompts. Also rename {{user_instruction}} →
{{user_profile}} in the chat template variable system for consistency.

Add build_workflow_user_profile helper that reuses shared fetch/format functions
from resolve_template_variables. Update contract and red-flag-dd workflow configs
to use the new variable names and add optional language input for contract output.
…t to example workflows

Append {{userProfile}} to LLM system prompts across contract-comparison, red-flag-dd, and folder-document-analysis workflows. Add language input parameter to folder-document-analysis for explicit output language control.
@larryro larryro merged commit 07a0b2f into main Mar 23, 2026
17 checks passed
@larryro larryro deleted the feat/user-context-template-variables branch March 23, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant