Files
zeekay 1b367e2b62 chore: rebase the tree onto upstream master
The tree was a debranded snapshot of upstream taken around 2026-02-20, and
upstream has moved about five months since. This replaces it with upstream
master, mechanically re-derived: bin/debrand does the rename, and the
pipeline and squashed migrations are restored from the shipped tree.

Not a merge. The previous import replaced the tree wholesale in a single
commit, so there is no shared content history to merge against. Reproducing
the rename on the new tree is what actually converges.

What survives: .hanzo/workflows, the Dockerfiles and bin/docker* entrypoints,
compose files, LLM.md, and insights/migrations. The squashed initial
migration is load-bearing — the live database records it by name, so
upstream's ~918 individual migrations cannot come back.

Nine products are dropped as unreferenced. Twenty-one more that we do not run
are kept anyway because the core app still imports them; unpicking those is a
refactor and does not belong in a rebase.

This base does not build yet, and the reasons are not in the rename:
upstream now wants Python 3.13.13 against our 3.12.12 and Django 5.2 against
our 4.2, and the dependency manifests still name upstream packages that we
republish under our own names. Those are decisions, not renames.
2026-08-01 15:44:40 -07:00

338 lines
14 KiB
Python

SESSION_REPLAY_EXAMPLES_PROMPT = """
<examples_and_rules>
## Examples and Rules
1. Combining Filters with the AND Operator
If you need to combine multiple filter conditions using the AND operator, structure them as follows:
json
{
"data": {
"date_from": "<date_from>",
"date_to": "<date_to>",
"duration": [{"key": "duration", "type": "recording", "value": 60, "operator": PropertyOperator.GreaterThan}], // Always include the duration filter.
"filter_group": {
"type": FilterLogicalOperator.AND,
"values": [
{
"type": FilterLogicalOperator.AND,
"values": [
{
"key": "<key>",
"type": "person", // e.g., PropertyFilterType.Person
"value": ["<value>"],
"operator": "icontains" // e.g., PropertyOperator.Exact or PropertyOperator.IContains
}
]
}
]
}
}
}
Notes
- Use FilterLogicalOperator.AND to ensure that all specified conditions must be met.
- The inner "values": [] array can include multiple filter items if needed.
2. Combining Filters with the OR Operator
When multiple conditions are acceptable (i.e., at least one must match), use the OR operator. The structure is similar, but with multiple groups in the outer array:
json
{
"data": {
"date_from": "<date_from>",
"date_to": "<date_to>",
"duration": [{"key": "duration", "type": "recording", "value": <duration>, "operator": PropertyOperator.GreaterThan}], // Use "gt", "lt", "gte", "lte"
"filter_group": {
"type": FilterLogicalOperator.OR,
"values": [
{
"type": FilterLogicalOperator.AND,
"values": [
{
"key": "<key>",
"type": PropertyFilterType.<Type>,
"value": ["<value>"],
"operator": PropertyOperator.<Operator>
}
]
},
{
"type": FilterLogicalOperator.AND,
"values": [
{
"key": "<key>",
"type": PropertyFilterType.<Type>,
"value": ["<value>"],
"operator": PropertyOperator.<Operator>
}
]
}
]
}
}
}
Notes:
- The outer group uses FilterLogicalOperator.OR, while each nested group uses FilterLogicalOperator.AND for its individual conditions.
- Multiple nested groups allow combining different filter criteria.
3. Operator Selection Guidelines
- Default Operators:
In most cases, the operator can be either exact or contains:
- For instance, if a user says, *"show me recordings where people visit login page"*, use the contains operator ("PropertyOperator.IContains") since the URL may include parameters.
- Exact Matching Example:
If a user says, *"show me recordings where people use mobile phone"*, use the exact operator to target a specific device type. For example:
json
{
"date_from": "<date_from>",
"date_to": "<date_to>",
"duration": [{"key": "duration", "type": "recording", "value": 60, "operator": PropertyOperator.GreaterThan}],
"filter_test_accounts": "<boolean>",
"filter_group": {
"type": FilterLogicalOperator.AND,
"values": [
{
"type": FilterLogicalOperator.AND,
"values": [
{
"key": "$device_type",
"type": "person",
"value": ["Mobile"],
"operator": "exact"
}
]
}
]
}
}
4. Special Cases
- Frustrated Users (Rageclicks):
If the query is to show recordings of people who are frustrated, filter for recordings containing a rageclick event. For example, use the event with:
- "id": "$rageclick", "name": "$rageclick", "type": "event"
- Users Facing Bugs/Errors/Problems:
For queries asking for recordings of users experiencing bugs or errors, target recordings with many console errors. An example filter might look like:
- Key: "level", Type: PropertyFilterType.Log_entry, Value: ["error"], Operator: PropertyOperator.Exact.
- Default Filter Group:
The blank, default `filter_group` value you can use is:
json
{
"type": "AND",
"values": [
{
"type": "AND",
"values": []
}
]
}
- Show all recordings / clean filters:
Return a default filter with default date range and no duration.
json
{
"data":
{
"order": "start_time",
"date_to": "null",
"duration": [{"key": "duration", "type": "recording", "value": 60, "operator": PropertyOperator.GreaterThan}],
"date_from": "-3d",
"filter_group": {"type": "AND", "values": [{"type": "AND", "values": []}]},
"filter_test_accounts": "true",
}
}
</examples_and_rules>
""".strip()
PRODUCT_DESCRIPTION_PROMPT = """
<agent_info>
You're Max, Insights's agent.
You are an expert at creating filters for Insights's session replay product based on the taxonomy of the user's data. Your job is to understand what users want to see in their data and translate that into precise filter configurations.
Transform natural language requests like "show me users from mobile devices who completed signup" into structured filter objects that will find exactly what users are looking for.
</agent_info>
<session_replay_details>
A session recording is a timeline of many events along with related entities a user has interacted with (directly or indirectly). When you apply a filter using an event property, the system returns any recording that contains at least one event matching that property/value pair.
</session_replay_details>
""".strip()
FILTER_OPTIONS_ITERATION_LIMIT_PROMPT = """I've tried several approaches but haven't been able to find the right filtering options. Could you please be more specific about what kind of filters you're looking for? For example:
- What type of events or actions are you interested in?
- What properties do you want to filter on?
- Are you looking for specific values or ranges?"""
FILTER_FIELDS_TAXONOMY_PROMPT = """
<filter_fields_taxonomy>
For the filter fields, you will find information on how to correctly discover the type of the filter field.
<key> Field
- Purpose:
The <key> represents the name of the property on which the filter is applied.
- Type Determination:
The expected data type can be inferred from the property_type field provided in each property object:
- "String" indicates the value should be a string.
- "Numeric" indicates a numeric value.
- "Boolean" indicates a boolean value.
- "DateTime", "Duration" and other types should follow their respective formats.
- A null value for property_type means the type is flexible or unspecified; in such cases, rely on the property name's context.
</key>
<value> Field
- Purpose:
The <value> field is an array containing one or more values that the filter should match.
- Data Type Matching:
Ensure the values in this array match the expected type of the property identified by <key>. For example:
- For a property with property_type "String", the value should be provided as a string (e.g., ["Mobile"]).
- For a property with property_type "Numeric", the value should be a number (e.g., [10]).
- For a property with property_type "Boolean", the value should be either true or false (e.g., [true]).
- Multiple Values:
The <value> array can contain multiple items when the filter should match any one of several potential values.
<supported_operators>
Supported operators for the String or Numeric types are:
- equals
- doesn't equal
- contains
- doesn't contain
- matches regex
- doesn't match regex
- is set
- is not set
Supported operators for the DateTime type are:
- equals
- doesn't equal
- greater than
- less than
- is set
- is not set
Supported operators for the Boolean type are:
- equals
- doesn't equal
- is set
- is not set
All operators take a single value except for `equals` and `doesn't equal` which can take one or more values.
</supported_operators>
</filter_fields_taxonomy>
""".strip()
DATE_FIELDS_PROMPT = """
<date_fields>
Below is a refined description for the date fields and their types:
<date_from>
- Relative Date (Days): Use the format "-Nd" for the last N days (e.g., "last 5 days" becomes "-5d", "yesterday" becomes "-1d").
- Relative Date (Hours): Use the format "-Nh" for the last N hours (e.g., "last 5 hours" becomes "-5h").
- Custom Date: If a specific start date is provided, use the format "YYYY-MM-DDT00:00:00:000".
- If a date is provided but without a year or month, use the current year and month.
- Default Behavior: If the user does not specify a date range, default to the last 3 days (i.e., use "-5d"). date_from MUST be set.
</date_from>
<date_to>
- Default Value: Set as null when the date range extends to today. Set as null when the user does not specify an end date.
- Custom Date: If a specific end date is required, use the format "YYYY-MM-DDT23:59:59:999".
</date_to>
</date_fields>
""".strip()
USER_FILTER_OPTIONS_PROMPT = """
Goal: {change}
Current filters: {current_filters}
DO NOT CHANGE THE CURRENT FILTERS. ONLY ADD NEW FILTERS or update the existing filters.
""".strip()
FILTER_EXAMPLES_PROMPT = """
<filter_examples>
# Logical Grouping
**AND**: All criteria must match (narrower results). Example: "mobile users from US" -> mobile AND US
**OR**: Any criteria can match (broader results). Example: "users from US or UK" -> US OR UK
**Simple AND** (most common):
```json
{"type":"AND","values":[{"type":"AND","values":[{"key":"$device_type","type":"session","operator":"exact","value":["Mobile"]},{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]}]}]}
```
**Simple OR**:
```json
{"type":"OR","values":[{"type":"AND","values":[{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]}]},{"type":"AND","values":[{"key":"$geoip_country_code","type":"person","operator":"exact","value":["UK"]}]}]}
```
**Complex (A OR B) AND (C OR D)**:
```json
{"type":"AND","values":[{"type":"OR","values":[{"key":"$device_type","type":"session","operator":"exact","value":["Mobile"]},{"key":"$device_type","type":"session","operator":"exact","value":["Tablet"]}]},{"type":"OR","values":[{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]},{"key":"$geoip_country_code","type":"person","operator":"exact","value":["UK"]}]}]}
```
**Complex (A AND B) OR (C AND D)**:
```json
{"type":"OR","values":[{"type":"AND","values":[{"key":"$device_type","type":"session","operator":"exact","value":["Mobile"]},{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]}]},{"type":"AND","values":[{"key":"$device_type","type":"session","operator":"exact","value":["Desktop"]},{"key":"$geoip_country_code","type":"person","operator":"exact","value":["UK"]}]}]}
```
# Common Properties
**Session**: `$device_type` (Mobile/Desktop/Tablet), `$browser`, `$os`, `$screen_width`, `$screen_height`
**Person**: `$geoip_country_code` (US/UK/FR), `$geoip_city_name`, custom fields
**Event**: `$current_url`, `$event_type` ($rageclick/$pageview), `$pathname`
**Recording**: `console_error_count`, `click_count`, `keypress_count`, `mouse_activity_count`, `activity_score`
Always use `"type": "recording"` for these. They are NOT events — `$keypress`, `$click`, `$console_error` do not exist as event names.
# Special Patterns
**Frustrated users (rageclicks)**:
```json
{"filter_group":{"type":"AND","values":[{"type":"AND","values":[{"key":"$event_type","type":"event","operator":"exact","value":["$rageclick"]}]}]}}
```
**Users with errors**:
```json
{"filter_group":{"type":"AND","values":[{"type":"AND","values":[{"key":"console_error_count","type":"recording","operator":"gt","value":[0]}]}]},"order":"console_error_count","order_direction":"DESC"}
```
**Recordings where users interacted with an element containing specific text**:
```json
{"filter_group":{"type":"AND","values":[{"type":"AND","values":[{"id":"$autocapture","type":"events","properties":[{"key":"text","type":"element","value":"Sign Up","operator":"icontains"}]}]}]}}
```
Valid element property keys: `tag_name` (HTML tag), `text` (visible text on the interacted element), `href` (link URL), `selector` (CSS selector).
**Clear all filters**:
```json
{"date_from":"-3d","date_to":null,"duration":[],"filter_group":{"type":"AND","values":[{"type":"AND","values":[]}]},"filter_test_accounts":true,"order":"start_time","order_direction":"DESC"}
```
# Complete Examples
**Mobile users from US (last 3 days)**:
```json
{"date_from":"-3d","date_to":null,"duration":[],"filter_group":{"type":"AND","values":[{"type":"AND","values":[{"key":"$device_type","type":"session","operator":"exact","value":["Mobile"]},{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]}]}]},"filter_test_accounts":true}
```
**US or UK users (last week)**:
```json
{"date_from":"-7d","date_to":null,"duration":[],"filter_group":{"type":"OR","values":[{"type":"AND","values":[{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]}]},{"type":"AND","values":[{"key":"$geoip_country_code","type":"person","operator":"exact","value":["UK"]}]}]},"filter_test_accounts":true}
```
**Long mobile sessions from paid customers on pricing page**:
```json
{"date_from":"-7d","date_to":null,"duration":[{"key":"duration","type":"recording","operator":"gt","value":300}],"filter_group":{"type":"AND","values":[{"type":"AND","values":[{"key":"plan_type","type":"person","operator":"exact","value":["paid"]},{"key":"$device_type","type":"session","operator":"exact","value":["Mobile"]},{"key":"$current_url","type":"event","operator":"icontains","value":["/pricing"]}]}]},"order":"duration","order_direction":"DESC","filter_test_accounts":true}
```
**Error tracking (yesterday)**:
```json
{"date_from":"-1d","date_to":null,"duration":[],"filter_group":{"type":"AND","values":[{"type":"AND","values":[{"key":"console_error_count","type":"recording","operator":"gt","value":[0]}]}]},"order":"console_error_count","order_direction":"DESC","filter_test_accounts":true}
```
**(Mobile OR Tablet) AND (US OR UK)**:
```json
{"date_from":"-3d","date_to":null,"duration":[],"filter_group":{"type":"AND","values":[{"type":"OR","values":[{"key":"$device_type","type":"session","operator":"exact","value":["Mobile"]},{"key":"$device_type","type":"session","operator":"exact","value":["Tablet"]}]},{"type":"OR","values":[{"key":"$geoip_country_code","type":"person","operator":"exact","value":["US"]},{"key":"$geoip_country_code","type":"person","operator":"exact","value":["UK"]}]}]},"filter_test_accounts":true}
</filter_examples>
""".strip()